Fix: 修复 MySQL DESC UPDATE 行内执行按钮解析 (#2243)
Co-authored-by: staff <staff@qimaos-MacBook-Pro.local>
This commit is contained in:
parent
ccb91784b3
commit
58e02fcae1
|
|
@ -183,6 +183,26 @@ describe("statementRangeAtCursor", () => {
|
|||
expect(range?.sql.trim()).toBe("EXPLAIN\nSELECT * FROM users");
|
||||
});
|
||||
|
||||
it("keeps MySQL DESC UPDATE joins as one statement", () => {
|
||||
const sql = "desc update test_orders a\njoin test_users b\non a.id=b.id \nset a.name = '张三'\nwhere b.id > 10;";
|
||||
expect(statementRangeAtCursor(sql, indexOf(sql, "desc"), "mysql")?.sql.trim()).toBe(sql.slice(0, -1));
|
||||
expect(statementRangeAtCursor(sql, indexOf(sql, "set"), "mysql")?.sql.trim()).toBe(sql.slice(0, -1));
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql, "mysql"))).toEqual([sql.slice(0, -1)]);
|
||||
});
|
||||
|
||||
it("keeps MySQL EXPLAIN UPDATE assignments as one statement", () => {
|
||||
const sql = "EXPLAIN UPDATE test_orders a\nJOIN test_users b ON a.id=b.id\nSET a.name = '张三'\nWHERE b.id > 10;";
|
||||
expect(statementRangeAtCursor(sql, indexOf(sql, "SET"), "mysql")?.sql.trim()).toBe(sql.slice(0, -1));
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql, "mysql"))).toEqual([sql.slice(0, -1)]);
|
||||
});
|
||||
|
||||
it("does not merge a plain MySQL DESC table statement with the next query", () => {
|
||||
const sql = "DESC users\nSELECT * FROM users;";
|
||||
expect(statementRangeAtCursor(sql, indexOf(sql, "DESC"), "mysql")?.sql.trim()).toBe("DESC users");
|
||||
expect(statementRangeAtCursor(sql, indexOf(sql, "SELECT"), "mysql")?.sql.trim()).toBe("SELECT * FROM users");
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql, "mysql"))).toEqual(["DESC users", "SELECT * FROM users"]);
|
||||
});
|
||||
|
||||
it("does not include comments between soft statement blocks", () => {
|
||||
const sql = "SELECT 1\n-- explain the next query\n/* still next query notes */\nSELECT 2;";
|
||||
const range = statementRangeAtCursor(sql, indexOf(sql, "1"));
|
||||
|
|
@ -355,6 +375,11 @@ describe("hasMultipleExecutionTargets", () => {
|
|||
const sql = "select COUNT(1) FROM your_table;\ndelimiter ;;\nselect COUNT(1) FROM your_table;\n\n;;\ndelimiter ;";
|
||||
expect(hasMultipleExecutionTargets(sql, "mysql")).toBe(true);
|
||||
});
|
||||
|
||||
it("does not show multiple targets for MySQL DESC UPDATE joins", () => {
|
||||
const sql = "desc update test_orders a\njoin test_users b\non a.id=b.id \nset a.name = '张三'\nwhere b.id > 10;";
|
||||
expect(hasMultipleExecutionTargets(sql, "mysql")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("supportsExecutionTargetPicker", () => {
|
||||
|
|
|
|||
|
|
@ -388,6 +388,8 @@ function splitStatementRangeAtSoftStarts(sql: string, statement: RawStatement, d
|
|||
|
||||
const boundaries: Array<{ hitFrom: number; from: number; keyword: string }> = [];
|
||||
let currentKeyword = softStatementKeywordAt(sql, statement.from, databaseType);
|
||||
let currentExplainTargetKeyword = explainLikeTargetKeywordAt(sql, statement.from);
|
||||
let currentBodyKeyword = currentExplainTargetKeyword ?? currentKeyword;
|
||||
let consumedWithMainStatement = false;
|
||||
let consumedExplainStatement = false;
|
||||
|
||||
|
|
@ -401,25 +403,28 @@ function splitStatementRangeAtSoftStarts(sql: string, statement: RawStatement, d
|
|||
continue;
|
||||
}
|
||||
|
||||
if (currentKeyword === "EXPLAIN" && !consumedExplainStatement && EXPLAIN_STATEMENT_KEYWORDS.has(lineStart.keyword)) {
|
||||
if (!consumedExplainStatement && EXPLAIN_STATEMENT_KEYWORDS.has(lineStart.keyword) && (currentKeyword === "EXPLAIN" || currentExplainTargetKeyword !== null)) {
|
||||
consumedExplainStatement = true;
|
||||
currentBodyKeyword = lineStart.keyword;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentKeyword === "CREATE" && CREATE_BODY_KEYWORDS.has(lineStart.keyword)) {
|
||||
if (currentBodyKeyword === "CREATE" && CREATE_BODY_KEYWORDS.has(lineStart.keyword)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentKeyword === "INSERT" && INSERT_BODY_KEYWORDS.has(lineStart.keyword)) {
|
||||
if (currentBodyKeyword === "INSERT" && INSERT_BODY_KEYWORDS.has(lineStart.keyword)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentKeyword === "UPDATE" && lineStart.keyword === "SET") {
|
||||
if (currentBodyKeyword === "UPDATE" && lineStart.keyword === "SET") {
|
||||
continue;
|
||||
}
|
||||
|
||||
boundaries.push(lineStart);
|
||||
currentKeyword = lineStart.keyword;
|
||||
currentExplainTargetKeyword = explainLikeTargetKeywordAt(sql, lineStart.from);
|
||||
currentBodyKeyword = currentExplainTargetKeyword ?? currentKeyword;
|
||||
consumedWithMainStatement = false;
|
||||
consumedExplainStatement = false;
|
||||
}
|
||||
|
|
@ -618,6 +623,22 @@ function softStatementStartKeywords(databaseType?: DatabaseType): Set<string> {
|
|||
return new Set([...COMMON_SOFT_STATEMENT_START_KEYWORDS, ...(databaseType ? (DATABASE_SOFT_STATEMENT_KEYWORDS[databaseType] ?? []) : [])]);
|
||||
}
|
||||
|
||||
function isExplainLikeKeyword(keyword: string | null): boolean {
|
||||
return keyword === "EXPLAIN" || keyword === "DESCRIBE" || keyword === "DESC";
|
||||
}
|
||||
|
||||
function explainLikeTargetKeywordAt(sql: string, pos: number): string | null {
|
||||
const prefixMatch = /^[A-Za-z_][\w$]*/.exec(sql.slice(pos));
|
||||
const prefix = prefixMatch?.[0]?.toUpperCase();
|
||||
if (!isExplainLikeKeyword(prefix ?? null)) return null;
|
||||
|
||||
let i = pos + (prefixMatch?.[0].length ?? 0);
|
||||
while (i < sql.length && isSqlWhitespace(sql[i])) i += 1;
|
||||
const targetMatch = /^[A-Za-z_][\w$]*/.exec(sql.slice(i));
|
||||
const targetKeyword = targetMatch?.[0]?.toUpperCase();
|
||||
return targetKeyword && EXPLAIN_STATEMENT_KEYWORDS.has(targetKeyword) ? targetKeyword : null;
|
||||
}
|
||||
|
||||
function startsLineComment(sql: string, pos: number): boolean {
|
||||
return (sql[pos] === "-" && sql[pos + 1] === "-") || sql[pos] === "#";
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue