fix(sql): 兼容 MySQL 建表注释选项拆分 (#2837)
Co-authored-by: zipg <4047349+zipg@users.noreply.github.com>
This commit is contained in:
parent
0901f176b0
commit
ae288a0345
|
|
@ -314,6 +314,48 @@ describe("statementRangeAtCursor", () => {
|
|||
expect(rangeSqlTexts(executableStatementRanges(sql, "mysql"))).toEqual([sql.slice(0, -1)]);
|
||||
});
|
||||
|
||||
it("keeps MySQL CREATE TABLE options with table comments", () => {
|
||||
const sql = `CREATE TABLE test_1 (
|
||||
id bigint NOT NULL AUTO_INCREMENT COMMENT '主键id',
|
||||
deleted tinyint NOT NULL DEFAULT 0 COMMENT '删除标志(0:有效 1:无效)',
|
||||
locked tinyint NOT NULL DEFAULT 0 COMMENT '是否锁定(0.否,1.是)',
|
||||
version int NOT NULL DEFAULT 0 COMMENT '版本号',
|
||||
creatorId bigint DEFAULT NULL COMMENT '创建人ID',
|
||||
createBy varchar(100) DEFAULT NULL COMMENT '创建人名称',
|
||||
createdTime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
updaterId bigint DEFAULT NULL COMMENT '修改人ID',
|
||||
updatedBy varchar(100) DEFAULT NULL COMMENT '修改人名称',
|
||||
updatedTime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
|
||||
PRIMARY KEY (id)
|
||||
)
|
||||
ENGINE = INNODB,
|
||||
CHARACTER SET utf8mb4,
|
||||
COLLATE utf8mb4_general_ci,
|
||||
COMMENT = '测试';`;
|
||||
|
||||
expect(statementRangeAtCursor(sql, indexOf(sql, "CREATE"), "mysql")?.sql.trim()).toBe(sql.slice(0, -1));
|
||||
expect(statementRangeAtCursor(sql, indexOf(sql, "COMMENT ="), "mysql")?.sql.trim()).toBe(sql.slice(0, -1));
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql, "mysql"))).toEqual([sql.slice(0, -1)]);
|
||||
expect(statementRangeAtCursor(sql, indexOf(sql, "COMMENT ="))?.sql.trim()).toBe(sql.slice(0, -1));
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql))).toEqual([sql.slice(0, -1)]);
|
||||
});
|
||||
|
||||
it("keeps MySQL CREATE TABLE comments without equals as table options", () => {
|
||||
const sql = "CREATE TABLE test_2 (\n id bigint NOT NULL\n)\nCOMMENT '测试';";
|
||||
|
||||
expect(statementRangeAtCursor(sql, indexOf(sql, "COMMENT"), "mysql")?.sql.trim()).toBe(sql.slice(0, -1));
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql, "mysql"))).toEqual([sql.slice(0, -1)]);
|
||||
expect(statementRangeAtCursor(sql, indexOf(sql, "COMMENT"))?.sql.trim()).toBe(sql.slice(0, -1));
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql))).toEqual([sql.slice(0, -1)]);
|
||||
});
|
||||
|
||||
it("does not merge standard COMMENT ON statements into preceding CREATE TABLE statements", () => {
|
||||
const sql = "CREATE TABLE users (id int)\nCOMMENT ON TABLE users IS 'Users';";
|
||||
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql, "postgres"))).toEqual(["CREATE TABLE users (id int)", "COMMENT ON TABLE users IS 'Users'"]);
|
||||
expect(rangeSqlTexts(executableStatementRanges(sql))).toEqual(["CREATE TABLE users (id int)", "COMMENT ON TABLE users IS 'Users'"]);
|
||||
});
|
||||
|
||||
it("keeps MySQL ALTER TABLE drop column clauses with the statement", () => {
|
||||
const sql = "ALTER TABLE t\n DROP COLUMN a,\n DROP COLUMN b;";
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ const SET_OPERATION_KEYWORDS = new Set(["UNION", "INTERSECT", "EXCEPT", "MINUS"]
|
|||
const SET_OPERATION_MODIFIER_KEYWORDS = new Set(["ALL", "DISTINCT"]);
|
||||
const ORACLE_LIKE_PL_SQL_DATABASES: ReadonlySet<DatabaseType> = new Set(["oracle", "dameng", "gaussdb", "yashandb", "oscar", "oceanbase-oracle"]);
|
||||
const MYSQL_ROUTINE_BLOCK_DATABASES: ReadonlySet<DatabaseType> = new Set(["mysql", "doris", "starrocks", "manticoresearch", "goldendb"]);
|
||||
const MYSQL_CREATE_TABLE_OPTION_DATABASES: ReadonlySet<DatabaseType> = new Set(["mysql", "doris", "starrocks", "manticoresearch", "goldendb", "gbase"]);
|
||||
const MYSQL_ROUTINE_OBJECT_TYPES = new Set(["PROCEDURE", "FUNCTION", "TRIGGER", "EVENT"]);
|
||||
const MYSQL_NON_ROUTINE_CREATE_TYPES = new Set(["DATABASE", "INDEX", "LOGFILE", "ROLE", "SCHEMA", "SERVER", "SPATIAL", "TABLE", "TEMPORARY", "UNIQUE", "USER", "VIEW"]);
|
||||
const MYSQL_CONTROL_BLOCK_SUFFIXES = new Set(["IF", "LOOP", "CASE", "REPEAT", "WHILE"]);
|
||||
|
|
@ -503,6 +504,10 @@ function splitStatementRangeAtSoftStarts(sql: string, statement: RawStatement, d
|
|||
continue;
|
||||
}
|
||||
|
||||
if (currentBodyKeyword === "CREATE" && isMysqlCreateTableOptionContinuation(sql, statement.from, lineStart.from, lineStart.keyword, databaseType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentBodyKeyword === "INSERT" && INSERT_BODY_KEYWORDS.has(lineStart.keyword)) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -730,6 +735,20 @@ function isSetOperationQueryContinuation(sql: string, from: number, to: number,
|
|||
return false;
|
||||
}
|
||||
|
||||
function isMysqlCreateTableOptionContinuation(sql: string, statementFrom: number, lineStartFrom: number, keyword: string, databaseType?: DatabaseType): boolean {
|
||||
if (databaseType && !MYSQL_CREATE_TABLE_OPTION_DATABASES.has(databaseType)) return false;
|
||||
if (keyword !== "COMMENT") return false;
|
||||
if (!startsWithMysqlCreateTable(sql, statementFrom)) return false;
|
||||
|
||||
const next = nextNonWhitespaceChar(sql, lineStartFrom + keyword.length);
|
||||
return next === "=" || next === "'" || next === '"';
|
||||
}
|
||||
|
||||
function startsWithMysqlCreateTable(sql: string, statementFrom: number): boolean {
|
||||
const text = sql.slice(statementFrom, statementFrom + 256);
|
||||
return /^CREATE\s+(?:TEMPORARY\s+)?TABLE\b/i.test(text);
|
||||
}
|
||||
|
||||
function topLevelWordsBefore(sql: string, from: number, to: number, limit: number): string[] {
|
||||
const words: string[] = [];
|
||||
let state: QuoteState | "lineComment" | "blockComment" = "none";
|
||||
|
|
|
|||
Loading…
Reference in New Issue