fix(sql): keep SQL Server table hints out of soft statement starts
This commit is contained in:
1 parent
d11d5acdfa
commit
a593a2b200
2 files changed
+44
No files matched your search
@@ -1254,6 +1254,45 @@ COMMENT = '测试';`;
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql))).toEqual([sql.slice(0, -1)]);
|
||||
});
|
||||
|
||||
it("keeps SQL Server table hints broken onto their own line with the host statement (#10098)", () => {
|
||||
const sql = "SELECT u.id\nFROM users u\nWITH (NOLOCK)\nWHERE u.id = 1\nSELECT 2;";
|
||||
const expected = "SELECT u.id\nFROM users u\nWITH (NOLOCK)\nWHERE u.id = 1";
|
||||
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql, "sqlserver"))).toEqual([expected, "SELECT 2"]);
|
||||
expect(statementRangeAtCursor(sql, indexOf(sql, "NOLOCK"), "sqlserver")?.sql.trim()).toBe(expected);
|
||||
expect(statementRangeAtCursor(sql, indexOf(sql, "WHERE"), "sqlserver")?.sql.trim()).toBe(expected);
|
||||
});
|
||||
|
||||
it("keeps JOIN table hints broken onto their own line with the host statement", () => {
|
||||
const sql = "SELECT *\nFROM a\nWITH (NOLOCK)\nJOIN b\nWITH (NOLOCK) ON a.id = b.id\nSELECT 2;";
|
||||
const expected = "SELECT *\nFROM a\nWITH (NOLOCK)\nJOIN b\nWITH (NOLOCK) ON a.id = b.id";
|
||||
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql, "sqlserver"))).toEqual([expected, "SELECT 2"]);
|
||||
});
|
||||
|
||||
it("keeps INSERT table hints broken onto their own line with the INSERT", () => {
|
||||
const sql = "INSERT INTO t\nWITH (TABLOCK) (id)\nVALUES (1)\nSELECT 2;";
|
||||
// INSERT ... SELECT keeps the source SELECT attached; the table-hint WITH
|
||||
// must not open a soft statement of its own inside the INSERT.
|
||||
const expected = "INSERT INTO t\nWITH (TABLOCK) (id)\nVALUES (1)\nSELECT 2";
|
||||
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql, "sqlserver"))).toEqual([expected]);
|
||||
expect(statementRangeAtCursor(sql, indexOf(sql, "TABLOCK"), "sqlserver")?.sql.trim()).toBe(expected);
|
||||
});
|
||||
|
||||
it("still treats a line-start CTE WITH as a soft statement start", () => {
|
||||
const sql = "SELECT 1\nWITH x AS (SELECT 2)\nSELECT * FROM x\nSELECT 3;";
|
||||
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql, "sqlserver"))).toEqual(["SELECT 1", "WITH x AS (SELECT 2)\nSELECT * FROM x", "SELECT 3"]);
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql))).toEqual(["SELECT 1", "WITH x AS (SELECT 2)\nSELECT * FROM x", "SELECT 3"]);
|
||||
});
|
||||
|
||||
it("still treats WITH RECURSIVE as a soft statement start", () => {
|
||||
const sql = "SELECT 1\nWITH RECURSIVE t AS (SELECT 2)\nSELECT * FROM t;";
|
||||
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql, "postgres"))).toEqual(["SELECT 1", "WITH RECURSIVE t AS (SELECT 2)\nSELECT * FROM t"]);
|
||||
});
|
||||
|
||||
it("keeps MySQL ALTER TABLE drop column clauses with the statement", () => {
|
||||
const sql = "ALTER TABLE t\n DROP COLUMN a,\n DROP COLUMN b;";
|
||||
|
||||
|
||||
@@ -1229,6 +1229,11 @@ function softStatementKeywordAt(sql: string, pos: number, databaseType?: Databas
|
||||
// COMMENT is also a common column name. Only COMMENT ON starts a standalone
|
||||
// SQL command; otherwise a line-start projection column must stay in SELECT.
|
||||
if (keyword === "COMMENT" && nextSqlWord(sql, pos + match[0].length, databaseType, parameterOptions) !== "ON") return null;
|
||||
// `WITH (` is a SQL Server table hint (`FROM t WITH (NOLOCK)`), not a CTE
|
||||
// opener — CTEs are always `WITH name AS (` / `WITH RECURSIVE name AS (`.
|
||||
// Formatters break table hints onto their own line; without this, the
|
||||
// following statement loses its run target (#10098).
|
||||
if (keyword === "WITH" && nextNonWhitespaceChar(sql, pos + match[0].length) === "(") return null;
|
||||
return softStatementStartKeywords(databaseType).has(keyword) ? keyword : null;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user