fix(sql): preserve TDSQL proxy directive

Closes #6043
This commit is contained in:
t8y2 committed 2026-08-12 17:02:19 +00:00
1 parent e18d1ddedf
commit 6f3895edd8
4 files changed
+138 -3

No files matched your search

@@ -13,6 +13,12 @@ describe("resolveExecutableSql", () => {
expect(resolveExecutableSql(sql, selectedSql, { mode: "current", cursorPos: cursorAfterFirstSemicolon })).toBe("select 2;");
});
it("keeps a manually selected proxy directive unchanged", () => {
const selectedSql = "/*proxy*/\nSHOW PROXY STATUS";
expect(resolveExecutableSql("SELECT 1;", selectedSql, { mode: "current", cursorPos: 0 })).toBe(selectedSql);
});
});
describe("executionCandidateForMode", () => {
@@ -1199,6 +1199,44 @@ describe("buildExecutionCandidates", () => {
expect(splitSqlStatementRanges("/*&tenant:mctest*/", "mysql")).toEqual([]);
});
it("preserves only the exact TDSQL proxy directive for the current statement", () => {
const directedSql = "/*proxy*/ \n\tSHOW PROXY STATUS";
const sql = `SELECT 1;\n${directedSql};\nSELECT 2;`;
const candidates = buildExecutionCandidates(sql, indexOf(sql, "STATUS"), "mysql");
expect(executionCandidateForMode(candidates, "current")?.sql).toBe(directedSql);
expect(executionCandidateForMode(candidates, "all")?.sql).toBe(sql);
expect(rangeSqlTexts(executableStatementRanges(sql, "mysql"))).toEqual(["SELECT 1", directedSql, "SELECT 2"]);
expect(splitSqlStatementRanges("/*proxy*/SHOW PROXY STATUS", "mysql")[0]?.sql).toBe("/*proxy*/SHOW PROXY STATUS");
expect(splitSqlStatementRanges("/* ordinary */\n/*proxy*/SHOW PROXY STATUS", "mysql")[0]?.sql).toBe("/*proxy*/SHOW PROXY STATUS");
expect(splitSqlStatementRanges("/*proxy*/", "mysql")).toEqual([]);
});
it.each(["/* ordinary */", "/*unknown*/", "/* proxy */", "/*PROXY*/"])("keeps %s as a non-executable leading comment", (comment) => {
const sql = `${comment}\nSHOW PROXY STATUS`;
const candidates = buildExecutionCandidates(sql, indexOf(sql, "STATUS"), "mysql");
expect(executionCandidateForMode(candidates, "current")?.sql).toBe("SHOW PROXY STATUS");
});
it.each(["/*proxy*/\n/* audit */\nSHOW PROXY STATUS", "/*proxy*/\n-- audit\nSHOW PROXY STATUS"])("does not preserve a proxy directive separated from SQL by another comment", (sql) => {
const candidates = buildExecutionCandidates(sql, indexOf(sql, "STATUS"), "mysql");
expect(executionCandidateForMode(candidates, "current")?.sql).toBe("SHOW PROXY STATUS");
});
it("does not preserve the proxy directive for other database types", () => {
const sql = "/*proxy*/\nSHOW PROXY STATUS";
const candidates = buildExecutionCandidates(sql, indexOf(sql, "STATUS"), "postgres");
expect(executionCandidateForMode(candidates, "current")?.sql).toBe("SHOW PROXY STATUS");
});
it("keeps existing hints without allowing them between the proxy directive and SQL", () => {
expect(splitSqlStatementRanges("/*+ route */\n/*proxy*/SHOW PROXY STATUS", "mysql")[0]?.sql).toBe("/*proxy*/SHOW PROXY STATUS");
expect(splitSqlStatementRanges("/*proxy*/\n/*+ route */\nSHOW PROXY STATUS", "mysql")[0]?.sql).toBe("/*+ route */\nSHOW PROXY STATUS");
});
it("uses the cursor statement for the first candidate when there is no selection", () => {
const sql = "SELECT *\nFROM users\nWHERE active = 1";
const candidates = buildExecutionCandidates(sql, indexOf(sql, "users"));
+10 -1
View File
@@ -297,6 +297,7 @@ export function splitSqlStatementRanges(sql: string, databaseType?: DatabaseType
let statementEnd = -1;
let statementHitStart = 0;
let pendingHintStart = -1;
let pendingProxyDirectiveStart = -1;
let customDelimiter: string | null = null;
let state: QuoteState = "none";
let dollarTag = "";
@@ -308,8 +309,9 @@ export function splitSqlStatementRanges(sql: string, databaseType?: DatabaseType
const markContent = (pos: number) => {
if (statementStart === -1) {
statementStart = pendingHintStart === -1 ? pos : pendingHintStart;
statementStart = pendingProxyDirectiveStart !== -1 ? pendingProxyDirectiveStart : pendingHintStart === -1 ? pos : pendingHintStart;
pendingHintStart = -1;
pendingProxyDirectiveStart = -1;
}
statementEnd = pos + 1;
};
@@ -318,6 +320,7 @@ export function splitSqlStatementRanges(sql: string, databaseType?: DatabaseType
if (statementStart === -1) {
statementEnd = -1;
pendingHintStart = -1;
pendingProxyDirectiveStart = -1;
postgresDollarQuotedRoutine = false;
oraclePlSqlStatementEnd = undefined;
return;
@@ -329,6 +332,7 @@ export function splitSqlStatementRanges(sql: string, databaseType?: DatabaseType
statementStart = -1;
statementEnd = -1;
pendingHintStart = -1;
pendingProxyDirectiveStart = -1;
postgresDollarQuotedRoutine = false;
oraclePlSqlStatementEnd = undefined;
};
@@ -433,11 +437,13 @@ export function splitSqlStatementRanges(sql: string, databaseType?: DatabaseType
// Line comments consume up to (and including) the newline.
if (ch === "-" && next === "-") {
pendingProxyDirectiveStart = -1;
const newline = sql.indexOf("\n", i);
i = newline === -1 ? len : newline + 1;
continue;
}
if (startsHashLineComment(sql, i, databaseType, parameterOptions)) {
pendingProxyDirectiveStart = -1;
const newline = sql.indexOf("\n", i);
i = newline === -1 ? len : newline + 1;
continue;
@@ -447,6 +453,9 @@ export function splitSqlStatementRanges(sql: string, databaseType?: DatabaseType
const hintMarker = sql[i + 2];
if (statementStart === -1 && pendingHintStart === -1 && (hintMarker === "+" || hintMarker === "@" || hintMarker === "&")) pendingHintStart = i;
const close = sql.indexOf("*/", i + 2);
if (statementStart === -1) {
pendingProxyDirectiveStart = databaseType === "mysql" && sql.startsWith("/*proxy*/", i) ? i : -1;
}
i = close === -1 ? len : close + 2;
continue;
}