const SIMPLE_LOWER_IDENTIFIER = /^[a-z_][a-z0-9_$]*$/; const SIMPLE_MYSQL_IDENTIFIER = /^[A-Za-z_$\u0080-\uFFFF][A-Za-z0-9_$\u0080-\uFFFF]*$/u; const SIMPLE_DAMENG_IDENTIFIER = /^[A-Z_][A-Z0-9_]*$/; const SIMPLE_ORACLE_IDENTIFIER = /^[A-Z][A-Z0-9_$#]*$/; // PostgreSQL pg_get_keywords() categories R and T. GaussDB's PostgreSQL- // compatible modes use the same identifier constraints for bare names. const POSTGRES_RESERVED_IDENTIFIER_KEYWORDS = new Set([ "all", "analyse", "analyze", "and", "any", "array", "as", "asc", "asymmetric", "authorization", "binary", "both", "case", "cast", "check", "collate", "collation", "column", "concurrently", "constraint", "create", "cross", "current_catalog", "current_date", "current_role", "current_schema", "current_time", "current_timestamp", "current_user", "default", "deferrable", "desc", "distinct", "do", "else", "end", "except", "false", "fetch", "for", "foreign", "freeze", "from", "full", "grant", "group", "having", "ilike", "in", "initially", "inner", "intersect", "into", "is", "isnull", "join", "lateral", "leading", "left", "like", "limit", "localtime", "localtimestamp", "natural", "not", "notnull", "null", "offset", "on", "only", "or", "order", "outer", "overlaps", "placing", "primary", "references", "returning", "right", "select", "session_user", "similar", "some", "symmetric", "system_user", "table", "tablesample", "then", "to", "trailing", "true", "union", "unique", "user", "using", "variadic", "verbose", "when", "where", "window", "with", ]); // GaussDB MySQL-compatible drivers report a backtick. These additional words // cover MySQL-only names that cannot safely be emitted as bare identifiers. const MYSQL_ONLY_RESERVED_IDENTIFIER_KEYWORDS = new Set([ "accessible", "auto_increment", "change", "database", "databases", "delayed", "describe", "div", "dual", "enclosed", "escaped", "explain", "force", "fulltext", "high_priority", "ignore", "index", "infile", "key", "keys", "kill", "linear", "lines", "load", "lock", "low_priority", "master_ssl_verify_server_cert", "maxvalue", "mediumint", "mod", "no_write_to_binlog", "optimize", "optionally", "outfile", "partition", "purge", "range", "read_write", "regexp", "release", "rename", "replace", "require", "rlike", "schema", "schemas", "separator", "show", "spatial", "sql_big_result", "sql_calc_found_rows", "sql_small_result", "ssl", "starting", "straight_join", "terminated", "tinyint", "unlock", "unsigned", "use", "utc_date", "utc_time", "utc_timestamp", "values", "varbinary", "varchar", "write", "xor", "zerofill", ]); // Oracle 11g SQL reserved words. Ordinary unquoted Oracle identifiers are // uppercase-folded, so only uppercase names outside this set are safe to unwrap. const ORACLE_RESERVED_IDENTIFIER_KEYWORDS = new Set([ "ACCESS", "ADD", "ALL", "ALTER", "AND", "ANY", "AS", "ASC", "AUDIT", "BETWEEN", "BY", "CHAR", "CHECK", "CLUSTER", "COLUMN", "COMMENT", "COMPRESS", "CONNECT", "CREATE", "CURRENT", "DATE", "DECIMAL", "DEFAULT", "DELETE", "DESC", "DISTINCT", "DROP", "ELSE", "EXCLUSIVE", "EXISTS", "FILE", "FLOAT", "FOR", "FROM", "GRANT", "GROUP", "HAVING", "IDENTIFIED", "IMMEDIATE", "IN", "INCREMENT", "INDEX", "INITIAL", "INSERT", "INTEGER", "INTERSECT", "INTO", "IS", "LEVEL", "LIKE", "LOCK", "LONG", "MAXEXTENTS", "MINUS", "MLSLABEL", "MODE", "MODIFY", "NOAUDIT", "NOCOMPRESS", "NOT", "NOWAIT", "NULL", "NUMBER", "OF", "OFFLINE", "ON", "ONLINE", "OPTION", "OR", "ORDER", "PCTFREE", "PRIOR", "PRIVILEGES", "PUBLIC", "RAW", "RENAME", "RESOURCE", "REVOKE", "ROW", "ROWID", "ROWNUM", "ROWS", "SELECT", "SESSION", "SET", "SHARE", "SIZE", "SMALLINT", "START", "SUCCESSFUL", "SYNONYM", "SYSDATE", "TABLE", "THEN", "TO", "TRIGGER", "UID", "UNION", "UNIQUE", "UPDATE", "USER", "VALIDATE", "VALUES", "VARCHAR", "VARCHAR2", "VIEW", "WHENEVER", "WHERE", "WITH", ]); // V$RESERVED_WORDS rows marked RESERVED = Y across the supported DM8 test // instances. DM's native identifier rules use uppercase ordinary names. const DAMENG_RESERVED_IDENTIFIER_KEYWORDS = new Set([ "ABSOLUTE", "ABSTRACT", "ADD", "ADMIN", "ALL", "ALTER", "AND", "ANY", "ARRAY", "ARRAYLEN", "AS", "ASC", "ASSIGN", "AUDIT", "AUTHORIZATION", "AUTO_INCREMENT", "BEGIN", "BETWEEN", "BIGDATEDIFF", "BINARY", "BOOL", "BOTH", "BREAK", "BSTRING", "BY", "BYTE", "CALL", "CASE", "CAST", "CATCH", "CHAR", "CHECK", "CLASS", "CLUSTER", "CLUSTERBTR", "COLLATION", "COLLECT", "COLUMN", "COMMENT", "COMMIT", "COMMITWORK", "CONNECT", "CONNECT_BY_ROOT", "CONST", "CONSTRAINT", "CONTAINS", "CONTEXT", "CONTINUE", "CONVERT", "CORRESPONDING", "CREATE", "CROSS", "CRYPTO", "CUBE", "CURRENT", "CURSOR", "DATEADD", "DATEDIFF", "DATEPART", "DECIMAL", "DECLARE", "DECODE", "DEFAULT", "DELETE", "DESC", "DISABLE", "DISKSPACE", "DISTINCT", "DISTRIBUTED", "DO", "DOMAIN", "DOUBLE", "DROP", "ELSE", "ELSEIF", "ELSIF", "ENABLE", "END", "EQU", "EXCHANGE", "EXEC", "EXECUTE", "EXISTS", "EXIT", "EXPLAIN", "EXTERN", "EXTRACT", "FETCH", "FINAL", "FINALLY", "FIRST", "FLASHBACK", "FLOAT", "FOR", "FOREIGN", "FROM", "FULL", "FULLY", "FUNCTION", "GET", "GOTO", "GRANT", "GROUP", "GROUPING", "HAVING", "IDENTITY", "IF", "IFNULL", "IMMEDIATE", "IN", "INDEX", "INLINE", "INNER", "INSERT", "INT", "INTERSECT", "INTERVAL", "INTO", "IS", "JOIN", "KEEP", "LEADING", "LEFT", "LEXER", "LIKE", "LIST", "LNNVL", "LOGIN", "LOOP", "MEMBER", "MINUS", "MULTISET", "NATURAL", "NEW", "NEXT", "NOCOPY", "NOCYCLE", "NOT", "NULL", "OBJECT", "OF", "ON", "OR", "ORDER", "OUT", "OVER", "OVERLAY", "OVERRIDE", "PARTITION", "PENDANT", "PERCENT", "PRIMARY", "PRINT", "PRIOR", "PRIVATE", "PRIVILEGES", "PROCEDURE", "PROTECTED", "PUBLIC", "RAISE", "RECORD", "REF", "REFERENCE", "REFERENCES", "REFERENCING", "RELATIVE", "REPEAT", "REPLICATE", "RETURN", "RETURNING", "REVERSE", "REVOKE", "RIGHT", "ROLLBACK", "ROLLUP", "ROW", "ROWNUM", "ROWS", "SAVEPOINT", "SBYTE", "SCHEMA", "SEALED", "SECTION", "SELECT", "SET", "SETS", "SHORT", "SIZEOF", "SOME", "STATIC", "STRUCT", "SUBPARTITION", "SWITCH", "SYNONYM", "TABLE", "THROW", "TIMESTAMPADD", "TIMESTAMPDIFF", "TO", "TOP", "TRAILING", "TRIGGER", "TRIM", "TRUNCATE", "TRY", "TYPEDEF", "TYPEOF", "UINT", "ULONG", "UNION", "UNIQUE", "UNTIL", "UPDATE", "USER", "USHORT", "USING", "VALUES", "VARRAY", "VERIFY", "VIEW", "VIRTUAL", "VOID", "WHEN", "WHENEVER", "WHERE", "WHILE", "WITH", "WITHIN", "XMLAGG", "XMLPARSE", "XMLTABLE", ]); export function isExplicitlyQuotedSqlIdentifier(value: string): boolean { if (value.length < 2) return false; return (value.startsWith('"') && value.endsWith('"')) || (value.startsWith("`") && value.endsWith("`")) || (value.startsWith("[") && value.endsWith("]")); } export function requiresPostgresIdentifierQuote(identifier: string, additionalKeywords?: ReadonlySet): boolean { if (!SIMPLE_LOWER_IDENTIFIER.test(identifier)) return true; return POSTGRES_RESERVED_IDENTIFIER_KEYWORDS.has(identifier) || additionalKeywords?.has(identifier) === true; } export function requiresMysqlIdentifierQuote(identifier: string, additionalKeywords?: ReadonlySet): boolean { if (!SIMPLE_MYSQL_IDENTIFIER.test(identifier)) return true; const normalized = identifier.toLowerCase(); return POSTGRES_RESERVED_IDENTIFIER_KEYWORDS.has(normalized) || additionalKeywords?.has(normalized) === true || MYSQL_ONLY_RESERVED_IDENTIFIER_KEYWORDS.has(normalized); } export function requiresOracleIdentifierQuote(identifier: string): boolean { return !SIMPLE_ORACLE_IDENTIFIER.test(identifier) || ORACLE_RESERVED_IDENTIFIER_KEYWORDS.has(identifier); } export function requiresDamengIdentifierQuote(identifier: string): boolean { return !SIMPLE_DAMENG_IDENTIFIER.test(identifier) || DAMENG_RESERVED_IDENTIFIER_KEYWORDS.has(identifier); } export function quoteGaussDbJdbcIdentifier(identifier: string, identifierQuote: string): string { if (isExplicitlyQuotedSqlIdentifier(identifier)) return identifier; const quote = identifierQuote.trim(); if (!quote) return identifier; const requiresQuote = quote === "`" ? requiresPostgresIdentifierQuote(identifier) || MYSQL_ONLY_RESERVED_IDENTIFIER_KEYWORDS.has(identifier.toLowerCase()) : requiresPostgresIdentifierQuote(identifier); if (!requiresQuote) return identifier; return `${quote}${identifier.replaceAll(quote, quote + quote)}${quote}`; }