diff --git a/src/Tokenizer.php b/src/Tokenizer.php index 2ac597d..35701d8 100644 --- a/src/Tokenizer.php +++ b/src/Tokenizer.php @@ -29,6 +29,7 @@ final class Tokenizer private array $reserved = [ 'ACCESSIBLE', 'ACTION', + 'ADD', 'AFTER', 'AGAINST', 'AGGREGATE', @@ -37,6 +38,7 @@ final class Tokenizer 'ALTER', 'ANALYSE', 'ANALYZE', + 'AND', 'AS', 'ASC', 'AUTOCOMMIT', @@ -44,12 +46,17 @@ final class Tokenizer 'BACKUP', 'BEGIN', 'BETWEEN', + 'BIGINT', + 'BINARY', 'BINLOG', + 'BLOB', 'BOTH', + 'BY', 'CASCADE', 'CASE', 'CHANGE', 'CHANGED', + 'CHAR', 'CHARACTER', 'CHARSET', 'CHECK', @@ -76,6 +83,7 @@ final class Tokenizer 'DAY_HOUR', 'DAY_MINUTE', 'DAY_SECOND', + 'DECIMAL', 'DEFAULT', 'DEFINER', 'DELAYED', @@ -87,6 +95,8 @@ final class Tokenizer 'DISTINCTROW', 'DIV', 'DO', + 'DOUBLE', + 'DROP', 'DUMPFILE', 'DUPLICATE', 'DYNAMIC', @@ -99,22 +109,29 @@ final class Tokenizer 'ESCAPE', 'ESCAPED', 'EVENTS', + 'EXCEPT', + 'EXCLUDE', 'EXEC', 'EXECUTE', 'EXISTS', 'EXPLAIN', 'EXTENDED', + 'FALSE', 'FAST', 'FIELDS', 'FILE', 'FILTER', 'FIRST', 'FIXED', + 'FLOAT', + 'FLOAT4', + 'FLOAT8', 'FLUSH', 'FOLLOWING', 'FOR', 'FORCE', 'FOREIGN', + 'FROM', 'FULL', 'FULLTEXT', 'FUNCTION', @@ -123,6 +140,7 @@ final class Tokenizer 'GRANTS', 'GROUP', 'GROUPS', + 'HAVING', 'HEAP', 'HIGH_PRIORITY', 'HOSTS', @@ -137,21 +155,33 @@ final class Tokenizer 'INDEX', 'INDEXES', 'INFILE', + 'INNER', 'INSERT', 'INSERT_ID', 'INSERT_METHOD', + 'INT', + 'INT1', + 'INT2', + 'INT3', + 'INT4', + 'INT8', + 'INTEGER', + 'INTERSECT', 'INTERVAL', 'INTO', 'INVOKER', 'IS', 'ISOLATION', + 'JOIN', 'KEY', 'KEYS', 'KILL', 'LAST_INSERT_ID', 'LEADING', + 'LEFT', 'LEVEL', 'LIKE', + 'LIMIT', 'LINEAR', 'LINES', 'LOAD', @@ -159,6 +189,9 @@ final class Tokenizer 'LOCK', 'LOCKS', 'LOGS', + 'LONG', + 'LONGBLOB', + 'LONGTEXT', 'LOW_PRIORITY', 'MARIA', 'MASTER', @@ -172,11 +205,15 @@ final class Tokenizer 'MAX_UPDATES_PER_HOUR', 'MAX_USER_CONNECTIONS', 'MEDIUM', + 'MEDIUMBLOB', + 'MEDIUMINT', + 'MEDIUMTEXT', 'MERGE', 'MINUTE', 'MINUTE_SECOND', 'MIN_ROWS', 'MODE', + 'MODIFY', 'MONTH', 'MRG_MYISAM', 'MYISAM', @@ -184,12 +221,16 @@ final class Tokenizer 'NATURAL', 'NOT', 'NULL', + 'NUMERIC', 'OFFSET', 'ON', 'OPEN', 'OPTIMIZE', 'OPTION', 'OPTIONALLY', + 'OR', + 'ORDER', + 'OUTER', 'OUTFILE', 'OVER', 'PACK_KEYS', @@ -214,6 +255,7 @@ final class Tokenizer 'READ', 'READ_ONLY', 'READ_WRITE', + 'REAL', 'RECURSIVE', 'REFERENCES', 'REGEXP', @@ -229,6 +271,7 @@ final class Tokenizer 'RETURN', 'RETURNS', 'REVOKE', + 'RIGHT', 'RLIKE', 'ROLLBACK', 'ROW', @@ -236,6 +279,7 @@ final class Tokenizer 'ROW_FORMAT', 'SECOND', 'SECURITY', + 'SELECT', 'SEPARATOR', 'SERIALIZABLE', 'SESSION', @@ -244,6 +288,7 @@ final class Tokenizer 'SHOW', 'SHUTDOWN', 'SLAVE', + 'SMALLINT', 'SONAME', 'SOUNDS', 'SQL', @@ -281,6 +326,9 @@ final class Tokenizer 'TERMINATED', 'THEN', 'TIES', + 'TINYBLOB', + 'TINYINT', + 'TINYTEXT', 'TO', 'TRAILING', 'TRANSACTIONAL', @@ -290,18 +338,27 @@ final class Tokenizer 'TYPES', 'UNBOUNDED', 'UNCOMMITTED', + 'UNION', 'UNIQUE', 'UNLOCK', 'UNSIGNED', + 'UPDATE', 'USAGE', 'USE', 'USING', + 'VALUES', + 'VARBINARY', + 'VARCHAR', + 'VARCHARACTER', 'VARIABLES', 'VIEW', 'WHEN', + 'WHERE', + 'WINDOW', 'WITH', 'WORK', 'WRITE', + 'XOR', 'YEAR_MONTH', ]; @@ -389,21 +446,16 @@ final class Tokenizer 'CEIL', 'CEILING', 'CENTROID', - 'CHAR', 'CHARACTER_LENGTH', - 'CHARSET', 'CHAR_LENGTH', 'CHECKSUM_AGG', 'COALESCE', 'COERCIBILITY', - 'COLLATION', 'COMPRESS', 'CONCAT', 'CONCAT_WS', 'CONNECTION_ID', - 'CONTAINS', 'CONV', - 'CONVERT', 'CONVERT_TZ', 'CONVEXHULL', 'COS', @@ -416,23 +468,19 @@ final class Tokenizer 'CURDATE', 'CURRENT_DATE', 'CURRENT_TIME', - 'CURRENT_TIMESTAMP', 'CURRENT_USER', 'CURTIME', - 'DATABASE', 'DATE', 'DATEDIFF', 'DATE_ADD', 'DATE_DIFF', 'DATE_FORMAT', 'DATE_SUB', - 'DAY', 'DAYNAME', 'DAYOFMONTH', 'DAYOFWEEK', 'DAYOFYEAR', 'DECODE', - 'DEFAULT', 'DEGREES', 'DENSE_RANK', 'DES_DECRYPT', @@ -480,17 +528,12 @@ final class Tokenizer 'GROUP_CONCAT', 'GROUP_UNIQUE_USERS', 'HEX', - 'HOUR', - 'IF', - 'IFNULL', 'INET_ATON', 'INET_NTOA', - 'INSERT', 'INSTR', 'INTERIORRINGN', 'INTERSECTION', 'INTERSECTS', - 'INTERVAL', 'ISCLOSED', 'ISEMPTY', 'ISNULL', @@ -500,12 +543,10 @@ final class Tokenizer 'IS_USED_LOCK', 'LAG', 'LAST_DAY', - 'LAST_INSERT_ID', 'LAST_VALUE', 'LCASE', 'LEAD', 'LEAST', - 'LEFT', 'LENGTH', 'LINEFROMTEXT', 'LINEFROMWKB', @@ -540,11 +581,9 @@ final class Tokenizer 'MICROSECOND', 'MID', 'MIN', - 'MINUTE', 'MLINEFROMTEXT', 'MLINEFROMWKB', 'MOD', - 'MONTH', 'MONTHNAME', 'MPOINTFROMTEXT', 'MPOINTFROMWKB', @@ -572,7 +611,6 @@ final class Tokenizer 'OLD_PASSWORD', 'ORD', 'OVERLAPS', - 'PASSWORD', 'PERCENTILE_CONT', 'PERCENTILE_DISC', 'PERCENT_RANK', @@ -600,16 +638,13 @@ final class Tokenizer 'RELATED', 'RELEASE_LOCK', 'REPEAT', - 'REPLACE', 'REVERSE', - 'RIGHT', 'ROUND', 'ROW_COUNT', 'ROW_NUMBER', 'RPAD', 'RTRIM', 'SCHEMA', - 'SECOND', 'SEC_TO_TIME', 'SESSION_USER', 'SHA', @@ -651,7 +686,6 @@ final class Tokenizer 'TOUCHES', 'TO_DAYS', 'TRIM', - 'TRUNCATE', 'UCASE', 'UNCOMPRESS', 'UNCOMPRESSED_LENGTH', diff --git a/tests/SqlFormatterTest.php b/tests/SqlFormatterTest.php index 92dd437..f5d6eb0 100644 --- a/tests/SqlFormatterTest.php +++ b/tests/SqlFormatterTest.php @@ -69,7 +69,7 @@ public function testHighlightBinary(): void $html = '
' .
'SELECT ' .
$binaryData .
- ' AS BINARY';
+ ' AS BINARY';
$this->assertSame($html, $this->formatter->highlight($sql));
}
diff --git a/tests/TokenizerTest.php b/tests/TokenizerTest.php
index f8a767e..d522ff1 100644
--- a/tests/TokenizerTest.php
+++ b/tests/TokenizerTest.php
@@ -12,7 +12,12 @@
use PHPUnit\Framework\TestCase;
use ReflectionClass;
+use function array_diff;
+use function array_diff_key;
use function array_filter;
+use function array_intersect;
+use function array_merge;
+use function array_unique;
use function implode;
use function preg_match;
use function serialize;
@@ -21,6 +26,1492 @@
final class TokenizerTest extends TestCase
{
+ /**
+ * Based on https://mariadb.com/kb/en/reserved-words/ list.
+ *
+ * All these keywords must be quoted.
+ */
+ private const KEYWORDS_RESERVED_MARIADB = [
+ 'ACCESSIBLE',
+ 'ADD',
+ 'ALL',
+ 'ALTER',
+ 'ANALYZE',
+ 'AND',
+ 'AS',
+ 'ASC',
+ 'ASENSITIVE',
+ 'BEFORE',
+ 'BETWEEN',
+ 'BIGINT',
+ 'BINARY',
+ 'BLOB',
+ 'BOTH',
+ 'BY',
+ 'CALL',
+ 'CASCADE',
+ 'CASE',
+ 'CHANGE',
+ 'CHAR',
+ 'CHARACTER',
+ 'CHECK',
+ 'COLLATE',
+ 'COLUMN',
+ 'CONDITION',
+ 'CONSTRAINT',
+ 'CONTINUE',
+ 'CONVERT',
+ 'CREATE',
+ 'CROSS',
+ 'CURRENT_DATE',
+ 'CURRENT_ROLE',
+ 'CURRENT_TIME',
+ 'CURRENT_TIMESTAMP',
+ 'CURRENT_USER',
+ 'CURSOR',
+ 'DATABASE',
+ 'DATABASES',
+ 'DAY_HOUR',
+ 'DAY_MICROSECOND',
+ 'DAY_MINUTE',
+ 'DAY_SECOND',
+ 'DEC',
+ 'DECIMAL',
+ 'DECLARE',
+ 'DEFAULT',
+ 'DELAYED',
+ 'DELETE',
+ 'DELETE_DOMAIN_ID',
+ 'DESC',
+ 'DESCRIBE',
+ 'DETERMINISTIC',
+ 'DISTINCT',
+ 'DISTINCTROW',
+ 'DIV',
+ 'DOUBLE',
+ 'DO_DOMAIN_IDS',
+ 'DROP',
+ 'DUAL',
+ 'EACH',
+ 'ELSE',
+ 'ELSEIF',
+ 'ENCLOSED',
+ 'ESCAPED',
+ 'EXCEPT',
+ 'EXISTS',
+ 'EXIT',
+ 'EXPLAIN',
+ 'FALSE',
+ 'FETCH',
+ 'FLOAT',
+ 'FLOAT4',
+ 'FLOAT8',
+ 'FOR',
+ 'FORCE',
+ 'FOREIGN',
+ 'FROM',
+ 'FULLTEXT',
+ 'GENERAL',
+ 'GRANT',
+ 'GROUP',
+ 'HAVING',
+ 'HIGH_PRIORITY',
+ 'HOUR_MICROSECOND',
+ 'HOUR_MINUTE',
+ 'HOUR_SECOND',
+ 'IF',
+ 'IGNORE',
+ 'IGNORE_DOMAIN_IDS',
+ 'IGNORE_SERVER_IDS',
+ 'IN',
+ 'INDEX',
+ 'INFILE',
+ 'INNER',
+ 'INOUT',
+ 'INSENSITIVE',
+ 'INSERT',
+ 'INT',
+ 'INT1',
+ 'INT2',
+ 'INT3',
+ 'INT4',
+ 'INT8',
+ 'INTEGER',
+ 'INTERSECT',
+ 'INTERVAL',
+ 'INTO',
+ 'IS',
+ 'ITERATE',
+ 'JOIN',
+ 'KEY',
+ 'KEYS',
+ 'KILL',
+ 'LEADING',
+ 'LEAVE',
+ 'LEFT',
+ 'LIKE',
+ 'LIMIT',
+ 'LINEAR',
+ 'LINES',
+ 'LOAD',
+ 'LOCALTIME',
+ 'LOCALTIMESTAMP',
+ 'LOCK',
+ 'LONG',
+ 'LONGBLOB',
+ 'LONGTEXT',
+ 'LOOP',
+ 'LOW_PRIORITY',
+ 'MASTER_HEARTBEAT_PERIOD',
+ 'MASTER_SSL_VERIFY_SERVER_CERT',
+ 'MATCH',
+ 'MAXVALUE',
+ 'MEDIUMBLOB',
+ 'MEDIUMINT',
+ 'MEDIUMTEXT',
+ 'MIDDLEINT',
+ 'MINUTE_MICROSECOND',
+ 'MINUTE_SECOND',
+ 'MOD',
+ 'MODIFIES',
+ 'NATURAL',
+ 'NOT',
+ 'NO_WRITE_TO_BINLOG',
+ 'NULL',
+ 'NUMERIC',
+ 'OFFSET',
+ 'ON',
+ 'OPTIMIZE',
+ 'OPTION',
+ 'OPTIONALLY',
+ 'OR',
+ 'ORDER',
+ 'OUT',
+ 'OUTER',
+ 'OUTFILE',
+ 'OVER',
+ 'PAGE_CHECKSUM',
+ 'PARSE_VCOL_EXPR',
+ 'PARTITION',
+ 'PRECISION',
+ 'PRIMARY',
+ 'PROCEDURE',
+ 'PURGE',
+ 'RANGE',
+ 'READ',
+ 'READS',
+ 'READ_WRITE',
+ 'REAL',
+ 'RECURSIVE',
+ 'REFERENCES',
+ 'REF_SYSTEM_ID',
+ 'REGEXP',
+ 'RELEASE',
+ 'RENAME',
+ 'REPEAT',
+ 'REPLACE',
+ 'REQUIRE',
+ 'RESIGNAL',
+ 'RESTRICT',
+ 'RETURN',
+ 'RETURNING',
+ 'REVOKE',
+ 'RIGHT',
+ 'RLIKE',
+ 'ROWS',
+ 'ROW_NUMBER',
+ 'SCHEMA',
+ 'SCHEMAS',
+ 'SECOND_MICROSECOND',
+ 'SELECT',
+ 'SENSITIVE',
+ 'SEPARATOR',
+ 'SET',
+ 'SHOW',
+ 'SIGNAL',
+ 'SLOW',
+ 'SMALLINT',
+ 'SPATIAL',
+ 'SPECIFIC',
+ 'SQL',
+ 'SQLEXCEPTION',
+ 'SQLSTATE',
+ 'SQLWARNING',
+ 'SQL_BIG_RESULT',
+ 'SQL_CALC_FOUND_ROWS',
+ 'SQL_SMALL_RESULT',
+ 'SSL',
+ 'STARTING',
+ 'STATS_AUTO_RECALC',
+ 'STATS_PERSISTENT',
+ 'STATS_SAMPLE_PAGES',
+ 'STRAIGHT_JOIN',
+ 'TABLE',
+ 'TERMINATED',
+ 'THEN',
+ 'TINYBLOB',
+ 'TINYINT',
+ 'TINYTEXT',
+ 'TO',
+ 'TRAILING',
+ 'TRIGGER',
+ 'TRUE',
+ 'UNDO',
+ 'UNION',
+ 'UNIQUE',
+ 'UNLOCK',
+ 'UNSIGNED',
+ 'UPDATE',
+ 'USAGE',
+ 'USE',
+ 'USING',
+ 'UTC_DATE',
+ 'UTC_TIME',
+ 'UTC_TIMESTAMP',
+ 'VALUES',
+ 'VARBINARY',
+ 'VARCHAR',
+ 'VARCHARACTER',
+ 'VARYING',
+ 'WHEN',
+ 'WHERE',
+ 'WHILE',
+ 'WINDOW',
+ 'WITH',
+ 'WRITE',
+ 'XOR',
+ 'YEAR_MONTH',
+ 'ZEROFILL',
+ ];
+
+ /**
+ * Based on https://learn.microsoft.com/en-us/sql/t-sql/language-elements/reserved-keywords-transact-sql?view=sql-server-ver16 list.
+ *
+ * All these keywords must be quoted.
+ */
+ private const KEYWORDS_RESERVED_MSSQL = [
+ 'ADD',
+ 'ALL',
+ 'ALTER',
+ 'AND',
+ 'ANY',
+ 'AS',
+ 'ASC',
+ 'AUTHORIZATION',
+ 'BACKUP',
+ 'BEGIN',
+ 'BETWEEN',
+ 'BREAK',
+ 'BROWSE',
+ 'BULK',
+ 'BY',
+ 'CASCADE',
+ 'CASE',
+ 'CHECK',
+ 'CHECKPOINT',
+ 'CLOSE',
+ 'CLUSTERED',
+ 'COALESCE',
+ 'COLLATE',
+ 'COLUMN',
+ 'COMMIT',
+ 'COMPUTE',
+ 'CONSTRAINT',
+ 'CONTAINS',
+ 'CONTAINSTABLE',
+ 'CONTINUE',
+ 'CONVERT',
+ 'CREATE',
+ 'CROSS',
+ 'CURRENT',
+ 'CURRENT_DATE',
+ 'CURRENT_TIME',
+ 'CURRENT_TIMESTAMP',
+ 'CURRENT_USER',
+ 'CURSOR',
+ 'DATABASE',
+ 'DBCC',
+ 'DEALLOCATE',
+ 'DECLARE',
+ 'DEFAULT',
+ 'DELETE',
+ 'DENY',
+ 'DESC',
+ 'DISK',
+ 'DISTINCT',
+ 'DISTRIBUTED',
+ 'DOUBLE',
+ 'DROP',
+ 'DUMP',
+ 'ELSE',
+ 'END',
+ 'ERRLVL',
+ 'ESCAPE',
+ 'EXCEPT',
+ 'EXEC',
+ 'EXECUTE',
+ 'EXISTS',
+ 'EXIT',
+ 'EXTERNAL',
+ 'FETCH',
+ 'FILE',
+ 'FILLFACTOR',
+ 'FOR',
+ 'FOREIGN',
+ 'FREETEXT',
+ 'FREETEXTTABLE',
+ 'FROM',
+ 'FULL',
+ 'FUNCTION',
+ 'GOTO',
+ 'GRANT',
+ 'GROUP',
+ 'HAVING',
+ 'HOLDLOCK',
+ 'IDENTITY',
+ 'IDENTITYCOL',
+ 'IDENTITY_INSERT',
+ 'IF',
+ 'IN',
+ 'INDEX',
+ 'INNER',
+ 'INSERT',
+ 'INTERSECT',
+ 'INTO',
+ 'IS',
+ 'JOIN',
+ 'KEY',
+ 'KILL',
+ 'LEFT',
+ 'LIKE',
+ 'LINENO',
+ 'LOAD',
+ 'MERGE',
+ 'NATIONAL',
+ 'NOCHECK',
+ 'NONCLUSTERED',
+ 'NOT',
+ 'NULL',
+ 'NULLIF',
+ 'OF',
+ 'OFF',
+ 'OFFSETS',
+ 'ON',
+ 'OPEN',
+ 'OPENDATASOURCE',
+ 'OPENQUERY',
+ 'OPENROWSET',
+ 'OPENXML',
+ 'OPTION',
+ 'OR',
+ 'ORDER',
+ 'OUTER',
+ 'OVER',
+ 'PERCENT',
+ 'PIVOT',
+ 'PLAN',
+ 'PRECISION',
+ 'PRIMARY',
+ 'PRINT',
+ 'PROC',
+ 'PROCEDURE',
+ 'PUBLIC',
+ 'RAISERROR',
+ 'READ',
+ 'READTEXT',
+ 'RECONFIGURE',
+ 'REFERENCES',
+ 'REPLICATION',
+ 'RESTORE',
+ 'RESTRICT',
+ 'RETURN',
+ 'REVERT',
+ 'REVOKE',
+ 'RIGHT',
+ 'ROLLBACK',
+ 'ROWCOUNT',
+ 'ROWGUIDCOL',
+ 'RULE',
+ 'SAVE',
+ 'SCHEMA',
+ 'SECURITYAUDIT',
+ 'SELECT',
+ 'SEMANTICKEYPHRASETABLE',
+ 'SEMANTICSIMILARITYDETAILSTABLE',
+ 'SEMANTICSIMILARITYTABLE',
+ 'SESSION_USER',
+ 'SET',
+ 'SETUSER',
+ 'SHUTDOWN',
+ 'SOME',
+ 'STATISTICS',
+ 'SYSTEM_USER',
+ 'TABLE',
+ 'TABLESAMPLE',
+ 'TEXTSIZE',
+ 'THEN',
+ 'TO',
+ 'TOP',
+ 'TRAN',
+ 'TRANSACTION',
+ 'TRIGGER',
+ 'TRUNCATE',
+ 'TRY_CONVERT',
+ 'TSEQUAL',
+ 'UNION',
+ 'UNIQUE',
+ 'UNPIVOT',
+ 'UPDATE',
+ 'UPDATETEXT',
+ 'USE',
+ 'USER',
+ 'VALUES',
+ 'VARYING',
+ 'VIEW',
+ 'WAITFOR',
+ 'WHEN',
+ 'WHERE',
+ 'WHILE',
+ 'WITH',
+ 'WITHIN GROUP',
+ 'WRITETEXT',
+ ];
+
+ /**
+ * Based on https://dev.mysql.com/doc/refman/8.4/en/keywords.html list.
+ *
+ * All these keywords must be quoted.
+ */
+ private const KEYWORDS_RESERVED_MYSQL = [
+ 'ACCESSIBLE',
+ 'ADD',
+ 'ALL',
+ 'ALTER',
+ 'ANALYZE',
+ 'AND',
+ 'AS',
+ 'ASC',
+ 'ASENSITIVE',
+ 'BEFORE',
+ 'BETWEEN',
+ 'BIGINT',
+ 'BINARY',
+ 'BLOB',
+ 'BOTH',
+ 'BY',
+ 'CALL',
+ 'CASCADE',
+ 'CASE',
+ 'CHANGE',
+ 'CHAR',
+ 'CHARACTER',
+ 'CHECK',
+ 'COLLATE',
+ 'COLUMN',
+ 'CONDITION',
+ 'CONSTRAINT',
+ 'CONTINUE',
+ 'CONVERT',
+ 'CREATE',
+ 'CROSS',
+ 'CUBE',
+ 'CUME_DIST',
+ 'CURRENT_DATE',
+ 'CURRENT_TIME',
+ 'CURRENT_TIMESTAMP',
+ 'CURRENT_USER',
+ 'CURSOR',
+ 'DATABASE',
+ 'DATABASES',
+ 'DAY_HOUR',
+ 'DAY_MICROSECOND',
+ 'DAY_MINUTE',
+ 'DAY_SECOND',
+ 'DEC',
+ 'DECIMAL',
+ 'DECLARE',
+ 'DEFAULT',
+ 'DELAYED',
+ 'DELETE',
+ 'DENSE_RANK',
+ 'DESC',
+ 'DESCRIBE',
+ 'DETERMINISTIC',
+ 'DISTINCT',
+ 'DISTINCTROW',
+ 'DIV',
+ 'DOUBLE',
+ 'DROP',
+ 'DUAL',
+ 'EACH',
+ 'ELSE',
+ 'ELSEIF',
+ 'EMPTY',
+ 'ENCLOSED',
+ 'ESCAPED',
+ 'EXCEPT',
+ 'EXISTS',
+ 'EXIT',
+ 'EXPLAIN',
+ 'FALSE',
+ 'FETCH',
+ 'FIRST_VALUE',
+ 'FLOAT',
+ 'FLOAT4',
+ 'FLOAT8',
+ 'FOR',
+ 'FORCE',
+ 'FOREIGN',
+ 'FROM',
+ 'FULLTEXT',
+ 'FUNCTION',
+ 'GENERATED',
+ 'GET',
+ 'GRANT',
+ 'GROUP',
+ 'GROUPING',
+ 'GROUPS',
+ 'HAVING',
+ 'HIGH_PRIORITY',
+ 'HOUR_MICROSECOND',
+ 'HOUR_MINUTE',
+ 'HOUR_SECOND',
+ 'IF',
+ 'IGNORE',
+ 'IN',
+ 'INDEX',
+ 'INFILE',
+ 'INNER',
+ 'INOUT',
+ 'INSENSITIVE',
+ 'INSERT',
+ 'INT',
+ 'INT1',
+ 'INT2',
+ 'INT3',
+ 'INT4',
+ 'INT8',
+ 'INTEGER',
+ 'INTERSECT',
+ 'INTERVAL',
+ 'INTO',
+ 'IO_AFTER_GTIDS',
+ 'IO_BEFORE_GTIDS',
+ 'IS',
+ 'ITERATE',
+ 'JOIN',
+ 'JSON_TABLE',
+ 'KEY',
+ 'KEYS',
+ 'KILL',
+ 'LAG',
+ 'LAST_VALUE',
+ 'LATERAL',
+ 'LEAD',
+ 'LEADING',
+ 'LEAVE',
+ 'LEFT',
+ 'LIKE',
+ 'LIMIT',
+ 'LINEAR',
+ 'LINES',
+ 'LOAD',
+ 'LOCALTIME',
+ 'LOCALTIMESTAMP',
+ 'LOCK',
+ 'LONG',
+ 'LONGBLOB',
+ 'LONGTEXT',
+ 'LOOP',
+ 'LOW_PRIORITY',
+ 'MANUAL',
+ 'MATCH',
+ 'MAXVALUE',
+ 'MEDIUMBLOB',
+ 'MEDIUMINT',
+ 'MEDIUMTEXT',
+ 'MIDDLEINT',
+ 'MINUTE_MICROSECOND',
+ 'MINUTE_SECOND',
+ 'MOD',
+ 'MODIFIES',
+ 'NATURAL',
+ 'NOT',
+ 'NO_WRITE_TO_BINLOG',
+ 'NTH_VALUE',
+ 'NTILE',
+ 'NULL',
+ 'NUMERIC',
+ 'OF',
+ 'ON',
+ 'OPTIMIZE',
+ 'OPTIMIZER_COSTS',
+ 'OPTION',
+ 'OPTIONALLY',
+ 'OR',
+ 'ORDER',
+ 'OUT',
+ 'OUTER',
+ 'OUTFILE',
+ 'OVER',
+ 'PARALLEL',
+ 'PARTITION',
+ 'PERCENT_RANK',
+ 'PRECISION',
+ 'PRIMARY',
+ 'PROCEDURE',
+ 'PURGE',
+ 'QUALIFY',
+ 'RANGE',
+ 'RANK',
+ 'READ',
+ 'READS',
+ 'READ_WRITE',
+ 'REAL',
+ 'RECURSIVE',
+ 'REFERENCES',
+ 'REGEXP',
+ 'RELEASE',
+ 'RENAME',
+ 'REPEAT',
+ 'REPLACE',
+ 'REQUIRE',
+ 'RESIGNAL',
+ 'RESTRICT',
+ 'RETURN',
+ 'REVOKE',
+ 'RIGHT',
+ 'RLIKE',
+ 'ROW',
+ 'ROWS',
+ 'ROW_NUMBER',
+ 'SCHEMA',
+ 'SCHEMAS',
+ 'SECOND_MICROSECOND',
+ 'SELECT',
+ 'SENSITIVE',
+ 'SEPARATOR',
+ 'SET',
+ 'SHOW',
+ 'SIGNAL',
+ 'SMALLINT',
+ 'SPATIAL',
+ 'SPECIFIC',
+ 'SQL',
+ 'SQLEXCEPTION',
+ 'SQLSTATE',
+ 'SQLWARNING',
+ 'SQL_BIG_RESULT',
+ 'SQL_CALC_FOUND_ROWS',
+ 'SQL_SMALL_RESULT',
+ 'SSL',
+ 'STARTING',
+ 'STORED',
+ 'STRAIGHT_JOIN',
+ 'SYSTEM',
+ 'TABLE',
+ 'TABLESAMPLE',
+ 'TERMINATED',
+ 'THEN',
+ 'TINYBLOB',
+ 'TINYINT',
+ 'TINYTEXT',
+ 'TO',
+ 'TRAILING',
+ 'TRIGGER',
+ 'TRUE',
+ 'UNDO',
+ 'UNION',
+ 'UNIQUE',
+ 'UNLOCK',
+ 'UNSIGNED',
+ 'UPDATE',
+ 'USAGE',
+ 'USE',
+ 'USING',
+ 'UTC_DATE',
+ 'UTC_TIME',
+ 'UTC_TIMESTAMP',
+ 'VALUES',
+ 'VARBINARY',
+ 'VARCHAR',
+ 'VARCHARACTER',
+ 'VARYING',
+ 'VIRTUAL',
+ 'WHEN',
+ 'WHERE',
+ 'WHILE',
+ 'WINDOW',
+ 'WITH',
+ 'WRITE',
+ 'XOR',
+ 'YEAR_MONTH',
+ 'ZEROFILL',
+ ];
+
+ /**
+ * Based on https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/Oracle-SQL-Reserved-Words.html list.
+ *
+ * All these keywords must be quoted.
+ */
+ private const KEYWORDS_RESERVED_ORACLE = [
+ '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',
+ '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',
+ ];
+
+ /**
+ * Based on https://www.postgresql.org/docs/16/sql-keywords-appendix.html list.
+ *
+ * All these keywords must be quoted.
+ */
+ private const KEYWORDS_RESERVED_POSTGRESQL = [
+ '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',
+ ];
+
+ /**
+ * Based on https://www.postgresql.org/docs/16/sql-keywords-appendix.html list.
+ *
+ * All these keywords must be quoted.
+ */
+ private const KEYWORDS_RESERVED_SQL2023 = [
+ 'ABS',
+ 'ABSENT',
+ 'ACOS',
+ 'ALL',
+ 'ALLOCATE',
+ 'ALTER',
+ 'AND',
+ 'ANY',
+ 'ANY_VALUE',
+ 'ARE',
+ 'ARRAY',
+ 'ARRAY_AGG',
+ 'ARRAY_MAX_CARDINALITY',
+ 'AS',
+ 'ASENSITIVE',
+ 'ASIN',
+ 'ASYMMETRIC',
+ 'AT',
+ 'ATAN',
+ 'ATOMIC',
+ 'AUTHORIZATION',
+ 'AVG',
+ 'BEGIN',
+ 'BEGIN_FRAME',
+ 'BEGIN_PARTITION',
+ 'BETWEEN',
+ 'BIGINT',
+ 'BINARY',
+ 'BLOB',
+ 'BOOLEAN',
+ 'BOTH',
+ 'BTRIM',
+ 'BY',
+ 'CALL',
+ 'CALLED',
+ 'CARDINALITY',
+ 'CASCADED',
+ 'CASE',
+ 'CAST',
+ 'CEIL',
+ 'CEILING',
+ 'CHAR',
+ 'CHARACTER',
+ 'CHARACTER_LENGTH',
+ 'CHAR_LENGTH',
+ 'CHECK',
+ 'CLASSIFIER',
+ 'CLOB',
+ 'CLOSE',
+ 'COALESCE',
+ 'COLLATE',
+ 'COLLECT',
+ 'COLUMN',
+ 'COMMIT',
+ 'CONDITION',
+ 'CONNECT',
+ 'CONSTRAINT',
+ 'CONTAINS',
+ 'CONVERT',
+ 'COPY',
+ 'CORR',
+ 'CORRESPONDING',
+ 'COS',
+ 'COSH',
+ 'COUNT',
+ 'COVAR_POP',
+ 'COVAR_SAMP',
+ 'CREATE',
+ 'CROSS',
+ 'CUBE',
+ 'CUME_DIST',
+ 'CURRENT',
+ 'CURRENT_CATALOG',
+ 'CURRENT_DATE',
+ 'CURRENT_DEFAULT_TRANSFORM_GROUP',
+ 'CURRENT_PATH',
+ 'CURRENT_ROLE',
+ 'CURRENT_ROW',
+ 'CURRENT_SCHEMA',
+ 'CURRENT_TIME',
+ 'CURRENT_TIMESTAMP',
+ 'CURRENT_TRANSFORM_GROUP_FOR_TYPE',
+ 'CURRENT_USER',
+ 'CURSOR',
+ 'CYCLE',
+ 'DATE',
+ 'DAY',
+ 'DEALLOCATE',
+ 'DEC',
+ 'DECFLOAT',
+ 'DECIMAL',
+ 'DECLARE',
+ 'DEFAULT',
+ 'DEFINE',
+ 'DELETE',
+ 'DENSE_RANK',
+ 'DEREF',
+ 'DESCRIBE',
+ 'DETERMINISTIC',
+ 'DISCONNECT',
+ 'DISTINCT',
+ 'DOUBLE',
+ 'DROP',
+ 'DYNAMIC',
+ 'EACH',
+ 'ELEMENT',
+ 'ELSE',
+ 'EMPTY',
+ 'END',
+ 'END-EXEC',
+ 'END_FRAME',
+ 'END_PARTITION',
+ 'EQUALS',
+ 'ESCAPE',
+ 'EVERY',
+ 'EXCEPT',
+ 'EXEC',
+ 'EXECUTE',
+ 'EXISTS',
+ 'EXP',
+ 'EXTERNAL',
+ 'EXTRACT',
+ 'FALSE',
+ 'FETCH',
+ 'FILTER',
+ 'FIRST_VALUE',
+ 'FLOAT',
+ 'FLOOR',
+ 'FOR',
+ 'FOREIGN',
+ 'FRAME_ROW',
+ 'FREE',
+ 'FROM',
+ 'FULL',
+ 'FUNCTION',
+ 'FUSION',
+ 'GET',
+ 'GLOBAL',
+ 'GRANT',
+ 'GREATEST',
+ 'GROUP',
+ 'GROUPING',
+ 'GROUPS',
+ 'HAVING',
+ 'HOLD',
+ 'HOUR',
+ 'IDENTITY',
+ 'IN',
+ 'INDICATOR',
+ 'INITIAL',
+ 'INNER',
+ 'INOUT',
+ 'INSENSITIVE',
+ 'INSERT',
+ 'INT',
+ 'INTEGER',
+ 'INTERSECT',
+ 'INTERSECTION',
+ 'INTERVAL',
+ 'INTO',
+ 'IS',
+ 'JOIN',
+ 'JSON',
+ 'JSON_ARRAY',
+ 'JSON_ARRAYAGG',
+ 'JSON_EXISTS',
+ 'JSON_OBJECT',
+ 'JSON_OBJECTAGG',
+ 'JSON_QUERY',
+ 'JSON_SCALAR',
+ 'JSON_SERIALIZE',
+ 'JSON_TABLE',
+ 'JSON_TABLE_PRIMITIVE',
+ 'JSON_VALUE',
+ 'LAG',
+ 'LANGUAGE',
+ 'LARGE',
+ 'LAST_VALUE',
+ 'LATERAL',
+ 'LEAD',
+ 'LEADING',
+ 'LEAST',
+ 'LEFT',
+ 'LIKE',
+ 'LIKE_REGEX',
+ 'LISTAGG',
+ 'LN',
+ 'LOCAL',
+ 'LOCALTIME',
+ 'LOCALTIMESTAMP',
+ 'LOG',
+ 'LOG10',
+ 'LOWER',
+ 'LPAD',
+ 'LTRIM',
+ 'MATCH',
+ 'MATCHES',
+ 'MATCH_NUMBER',
+ 'MATCH_RECOGNIZE',
+ 'MAX',
+ 'MEMBER',
+ 'MERGE',
+ 'METHOD',
+ 'MIN',
+ 'MINUTE',
+ 'MOD',
+ 'MODIFIES',
+ 'MODULE',
+ 'MONTH',
+ 'MULTISET',
+ 'NATIONAL',
+ 'NATURAL',
+ 'NCHAR',
+ 'NCLOB',
+ 'NEW',
+ 'NO',
+ 'NONE',
+ 'NORMALIZE',
+ 'NOT',
+ 'NTH_VALUE',
+ 'NTILE',
+ 'NULL',
+ 'NULLIF',
+ 'NUMERIC',
+ 'OCCURRENCES_REGEX',
+ 'OCTET_LENGTH',
+ 'OF',
+ 'OFFSET',
+ 'OLD',
+ 'OMIT',
+ 'ON',
+ 'ONE',
+ 'ONLY',
+ 'OPEN',
+ 'OR',
+ 'ORDER',
+ 'OUT',
+ 'OUTER',
+ 'OVER',
+ 'OVERLAPS',
+ 'OVERLAY',
+ 'PARAMETER',
+ 'PARTITION',
+ 'PATTERN',
+ 'PER',
+ 'PERCENT',
+ 'PERCENTILE_CONT',
+ 'PERCENTILE_DISC',
+ 'PERCENT_RANK',
+ 'PERIOD',
+ 'PORTION',
+ 'POSITION',
+ 'POSITION_REGEX',
+ 'POWER',
+ 'PRECEDES',
+ 'PRECISION',
+ 'PREPARE',
+ 'PRIMARY',
+ 'PROCEDURE',
+ 'PTF',
+ 'RANGE',
+ 'RANK',
+ 'READS',
+ 'REAL',
+ 'RECURSIVE',
+ 'REF',
+ 'REFERENCES',
+ 'REFERENCING',
+ 'REGR_AVGX',
+ 'REGR_AVGY',
+ 'REGR_COUNT',
+ 'REGR_INTERCEPT',
+ 'REGR_R2',
+ 'REGR_SLOPE',
+ 'REGR_SXX',
+ 'REGR_SXY',
+ 'REGR_SYY',
+ 'RELEASE',
+ 'RESULT',
+ 'RETURN',
+ 'RETURNS',
+ 'REVOKE',
+ 'RIGHT',
+ 'ROLLBACK',
+ 'ROLLUP',
+ 'ROW',
+ 'ROWS',
+ 'ROW_NUMBER',
+ 'RPAD',
+ 'RUNNING',
+ 'SAVEPOINT',
+ 'SCOPE',
+ 'SCROLL',
+ 'SEARCH',
+ 'SECOND',
+ 'SEEK',
+ 'SELECT',
+ 'SENSITIVE',
+ 'SESSION_USER',
+ 'SET',
+ 'SHOW',
+ 'SIMILAR',
+ 'SIN',
+ 'SINH',
+ 'SKIP',
+ 'SMALLINT',
+ 'SOME',
+ 'SPECIFIC',
+ 'SPECIFICTYPE',
+ 'SQL',
+ 'SQLEXCEPTION',
+ 'SQLSTATE',
+ 'SQLWARNING',
+ 'SQRT',
+ 'START',
+ 'STATIC',
+ 'STDDEV_POP',
+ 'STDDEV_SAMP',
+ 'SUBMULTISET',
+ 'SUBSET',
+ 'SUBSTRING',
+ 'SUBSTRING_REGEX',
+ 'SUCCEEDS',
+ 'SUM',
+ 'SYMMETRIC',
+ 'SYSTEM',
+ 'SYSTEM_TIME',
+ 'SYSTEM_USER',
+ 'TABLE',
+ 'TABLESAMPLE',
+ 'TAN',
+ 'TANH',
+ 'THEN',
+ 'TIME',
+ 'TIMESTAMP',
+ 'TIMEZONE_HOUR',
+ 'TIMEZONE_MINUTE',
+ 'TO',
+ 'TRAILING',
+ 'TRANSLATE',
+ 'TRANSLATE_REGEX',
+ 'TRANSLATION',
+ 'TREAT',
+ 'TRIGGER',
+ 'TRIM',
+ 'TRIM_ARRAY',
+ 'TRUE',
+ 'TRUNCATE',
+ 'UESCAPE',
+ 'UNION',
+ 'UNIQUE',
+ 'UNKNOWN',
+ 'UNNEST',
+ 'UPDATE',
+ 'UPPER',
+ 'USER',
+ 'USING',
+ 'VALUE',
+ 'VALUES',
+ 'VALUE_OF',
+ 'VARBINARY',
+ 'VARCHAR',
+ 'VARYING',
+ 'VAR_POP',
+ 'VAR_SAMP',
+ 'VERSIONING',
+ 'WHEN',
+ 'WHENEVER',
+ 'WHERE',
+ 'WIDTH_BUCKET',
+ 'WINDOW',
+ 'WITH',
+ 'WITHIN',
+ 'WITHOUT',
+ 'YEAR',
+ ];
+
+ /**
+ * Based on https://www.sqlite.org/lang_keywords.html list.
+ *
+ * All these keywords must be quoted.
+ */
+ private const KEYWORDS_RESERVED_SQLITE = [
+ 'ABORT',
+ 'ACTION',
+ 'ADD',
+ 'AFTER',
+ 'ALL',
+ 'ALTER',
+ 'ALWAYS',
+ 'ANALYZE',
+ 'AND',
+ 'AS',
+ 'ASC',
+ 'ATTACH',
+ 'AUTOINCREMENT',
+ 'BEFORE',
+ 'BEGIN',
+ 'BETWEEN',
+ 'BY',
+ 'CASCADE',
+ 'CASE',
+ 'CAST',
+ 'CHECK',
+ 'COLLATE',
+ 'COLUMN',
+ 'COMMIT',
+ 'CONFLICT',
+ 'CONSTRAINT',
+ 'CREATE',
+ 'CROSS',
+ 'CURRENT',
+ 'CURRENT_DATE',
+ 'CURRENT_TIME',
+ 'CURRENT_TIMESTAMP',
+ 'DATABASE',
+ 'DEFAULT',
+ 'DEFERRABLE',
+ 'DEFERRED',
+ 'DELETE',
+ 'DESC',
+ 'DETACH',
+ 'DISTINCT',
+ 'DO',
+ 'DROP',
+ 'EACH',
+ 'ELSE',
+ 'END',
+ 'ESCAPE',
+ 'EXCEPT',
+ 'EXCLUDE',
+ 'EXCLUSIVE',
+ 'EXISTS',
+ 'EXPLAIN',
+ 'FAIL',
+ 'FILTER',
+ 'FIRST',
+ 'FOLLOWING',
+ 'FOR',
+ 'FOREIGN',
+ 'FROM',
+ 'FULL',
+ 'GENERATED',
+ 'GLOB',
+ 'GROUP',
+ 'GROUPS',
+ 'HAVING',
+ 'IF',
+ 'IGNORE',
+ 'IMMEDIATE',
+ 'IN',
+ 'INDEX',
+ 'INDEXED',
+ 'INITIALLY',
+ 'INNER',
+ 'INSERT',
+ 'INSTEAD',
+ 'INTERSECT',
+ 'INTO',
+ 'IS',
+ 'ISNULL',
+ 'JOIN',
+ 'KEY',
+ 'LAST',
+ 'LEFT',
+ 'LIKE',
+ 'LIMIT',
+ 'MATCH',
+ 'MATERIALIZED',
+ 'NATURAL',
+ 'NO',
+ 'NOT',
+ 'NOTHING',
+ 'NOTNULL',
+ 'NULL',
+ 'NULLS',
+ 'OF',
+ 'OFFSET',
+ 'ON',
+ 'OR',
+ 'ORDER',
+ 'OTHERS',
+ 'OUTER',
+ 'OVER',
+ 'PARTITION',
+ 'PLAN',
+ 'PRAGMA',
+ 'PRECEDING',
+ 'PRIMARY',
+ 'QUERY',
+ 'RAISE',
+ 'RANGE',
+ 'RECURSIVE',
+ 'REFERENCES',
+ 'REGEXP',
+ 'REINDEX',
+ 'RELEASE',
+ 'RENAME',
+ 'REPLACE',
+ 'RESTRICT',
+ 'RETURNING',
+ 'RIGHT',
+ 'ROLLBACK',
+ 'ROW',
+ 'ROWS',
+ 'SAVEPOINT',
+ 'SELECT',
+ 'SET',
+ 'TABLE',
+ 'TEMP',
+ 'TEMPORARY',
+ 'THEN',
+ 'TIES',
+ 'TO',
+ 'TRANSACTION',
+ 'TRIGGER',
+ 'UNBOUNDED',
+ 'UNION',
+ 'UNIQUE',
+ 'UPDATE',
+ 'USING',
+ 'VACUUM',
+ 'VALUES',
+ 'VIEW',
+ 'VIRTUAL',
+ 'WHEN',
+ 'WHERE',
+ 'WINDOW',
+ 'WITH',
+ 'WITHOUT',
+ ];
+
/**
* @param 'reserved'|'reservedToplevel'|'reservedNewline'|'functions' $propertyName
*
@@ -43,6 +1534,13 @@ public function testInternalKeywordListsAreSortedForEasierMaintenance(): void
$this->getTokenizerList('reservedToplevel'),
$this->getTokenizerList('reservedNewline'),
$this->getTokenizerList('functions'),
+ self::KEYWORDS_RESERVED_MARIADB,
+ self::KEYWORDS_RESERVED_MSSQL,
+ self::KEYWORDS_RESERVED_MYSQL,
+ self::KEYWORDS_RESERVED_ORACLE,
+ self::KEYWORDS_RESERVED_POSTGRESQL,
+ self::KEYWORDS_RESERVED_SQL2023,
+ self::KEYWORDS_RESERVED_SQLITE,
] as $list
) {
$listSorted = $list;
@@ -52,17 +1550,51 @@ public function testInternalKeywordListsAreSortedForEasierMaintenance(): void
}
}
- public function testKeywordsReservedAreSingleUpperWord(): void
+ public function testKeywordsAreSingleUpperWord(): void
{
- $tokenizerReserved = $this->getTokenizerList('reserved');
+ $tokenizerKeywords = array_unique(array_merge(
+ $this->getTokenizerList('reserved'),
+ $this->getTokenizerList('functions'),
+ ));
- $kwsDiff = array_filter($tokenizerReserved, static function ($v) {
+ $kwsDiff = array_filter($tokenizerKeywords, static function ($v) {
return $v !== strtoupper($v) || preg_match('~^\w+$~', $v) !== 1;
});
self::assertSame([], $kwsDiff);
}
+ public function testKeywordsAreDisjunctive(): void
+ {
+ $tokenizerKeywords = array_merge(
+ $this->getTokenizerList('reserved'),
+ $this->getTokenizerList('functions'),
+ );
+
+ self::assertSame(
+ [],
+ array_diff_key($tokenizerKeywords, array_unique($tokenizerKeywords)),
+ );
+ }
+
+ public function testKeywordsReservedContainAllIntersectedReservedKeywords(): void
+ {
+ $tokenizerReserved = $this->getTokenizerList('reserved');
+
+ self::assertSame(
+ [],
+ array_diff(array_unique(array_intersect(
+ self::KEYWORDS_RESERVED_MARIADB,
+ self::KEYWORDS_RESERVED_MSSQL,
+ self::KEYWORDS_RESERVED_MYSQL,
+ self::KEYWORDS_RESERVED_ORACLE,
+ self::KEYWORDS_RESERVED_POSTGRESQL,
+ self::KEYWORDS_RESERVED_SQL2023,
+ self::KEYWORDS_RESERVED_SQLITE,
+ )), $tokenizerReserved),
+ );
+ }
+
/** @param listCREATE TABLE `PREFIX_address` ( - `id_address` int(10) unsigned NOT NULL auto_increment, - `id_country` int(10) unsigned NOT NULL, - `id_state` int(10) unsigned default NULL, - `id_customer` int(10) unsigned NOT NULL default '0', - `id_manufacturer` int(10) unsigned NOT NULL default '0', - `id_supplier` int(10) unsigned NOT NULL default '0', - `id_warehouse` int(10) unsigned NOT NULL default '0', - `alias` varchar(32) NOT NULL, - `company` varchar(64) default NULL, - `lastname` varchar(32) NOT NULL, - `firstname` varchar(32) NOT NULL, - `address1` varchar(128) NOT NULL, - `address2` varchar(128) default NULL, - `postcode` varchar(12) default NULL, - `city` varchar(64) NOT NULL, + `id_address` int(10) unsigned NOT NULL auto_increment, + `id_country` int(10) unsigned NOT NULL, + `id_state` int(10) unsigned default NULL, + `id_customer` int(10) unsigned NOT NULL default '0', + `id_manufacturer` int(10) unsigned NOT NULL default '0', + `id_supplier` int(10) unsigned NOT NULL default '0', + `id_warehouse` int(10) unsigned NOT NULL default '0', + `alias` varchar(32) NOT NULL, + `company` varchar(64) default NULL, + `lastname` varchar(32) NOT NULL, + `firstname` varchar(32) NOT NULL, + `address1` varchar(128) NOT NULL, + `address2` varchar(128) default NULL, + `postcode` varchar(12) default NULL, + `city` varchar(64) NOT NULL, `other` text, - `phone` varchar(16) default NULL, - `phone_mobile` varchar(16) default NULL, - `vat_number` varchar(32) default NULL, - `dni` varchar(16) DEFAULT NULL, + `phone` varchar(16) default NULL, + `phone_mobile` varchar(16) default NULL, + `vat_number` varchar(32) default NULL, + `dni` varchar(16) DEFAULT NULL, `date_add` datetime NOT NULL, `date_upd` datetime NOT NULL, - `active` tinyint(1) unsigned NOT NULL default '1', - `deleted` tinyint(1) unsigned NOT NULL default '0', + `active` tinyint(1) unsigned NOT NULL default '1', + `deleted` tinyint(1) unsigned NOT NULL default '0', PRIMARY KEY (`id_address`), KEY `address_customer` (`id_customer`), KEY `id_country` (`id_country`), @@ -80,51 +80,51 @@ ) ENGINE = ENGINE_TYPE DEFAULT CHARSET = utf8---
CREATE TABLE `PREFIX_alias` ( - `id_alias` int(10) unsigned NOT NULL auto_increment, - `alias` varchar(255) NOT NULL, - `search` varchar(255) NOT NULL, - `active` tinyint(1) NOT NULL default '1', + `id_alias` int(10) unsigned NOT NULL auto_increment, + `alias` varchar(255) NOT NULL, + `search` varchar(255) NOT NULL, + `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`id_alias`), UNIQUE KEY `alias` (`alias`) ) ENGINE = ENGINE_TYPE DEFAULT CHARSET = utf8---
CREATE TABLE `PREFIX_carrier` ( - `id_carrier` int(10) unsigned NOT NULL AUTO_INCREMENT, - `id_reference` int(10) unsigned NOT NULL, - `id_tax_rules_group` int(10) unsigned DEFAULT '0', - `name` varchar(64) NOT NULL, - `url` varchar(255) DEFAULT NULL, - `active` tinyint(1) unsigned NOT NULL DEFAULT '0', - `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0', - `shipping_handling` tinyint(1) unsigned NOT NULL DEFAULT '1', - `range_behavior` tinyint(1) unsigned NOT NULL DEFAULT '0', - `is_module` tinyint(1) unsigned NOT NULL DEFAULT '0', - `is_free` tinyint(1) unsigned NOT NULL DEFAULT '0', - `shipping_external` tinyint(1) unsigned NOT NULL DEFAULT '0', - `need_range` tinyint(1) unsigned NOT NULL DEFAULT '0', - `external_module_name` varchar(64) DEFAULT NULL, - `shipping_method` int(2) NOT NULL DEFAULT '0', - `position` int(10) unsigned NOT NULL default '0', - `max_width` int(10) DEFAULT 0, - `max_height` int(10) DEFAULT 0, - `max_depth` int(10) DEFAULT 0, - `max_weight` int(10) DEFAULT 0, - `grade` int(10) DEFAULT 0, + `id_carrier` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id_reference` int(10) unsigned NOT NULL, + `id_tax_rules_group` int(10) unsigned DEFAULT '0', + `name` varchar(64) NOT NULL, + `url` varchar(255) DEFAULT NULL, + `active` tinyint(1) unsigned NOT NULL DEFAULT '0', + `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0', + `shipping_handling` tinyint(1) unsigned NOT NULL DEFAULT '1', + `range_behavior` tinyint(1) unsigned NOT NULL DEFAULT '0', + `is_module` tinyint(1) unsigned NOT NULL DEFAULT '0', + `is_free` tinyint(1) unsigned NOT NULL DEFAULT '0', + `shipping_external` tinyint(1) unsigned NOT NULL DEFAULT '0', + `need_range` tinyint(1) unsigned NOT NULL DEFAULT '0', + `external_module_name` varchar(64) DEFAULT NULL, + `shipping_method` int(2) NOT NULL DEFAULT '0', + `position` int(10) unsigned NOT NULL default '0', + `max_width` int(10) DEFAULT 0, + `max_height` int(10) DEFAULT 0, + `max_depth` int(10) DEFAULT 0, + `max_weight` int(10) DEFAULT 0, + `grade` int(10) DEFAULT 0, PRIMARY KEY (`id_carrier`), KEY `deleted` (`deleted`, `active`), KEY `id_tax_rules_group` (`id_tax_rules_group`) ) ENGINE = ENGINE_TYPE DEFAULT CHARSET = utf8---
CREATE TABLE IF NOT EXISTS `PREFIX_specific_price_rule` ( - `id_specific_price_rule` int(10) unsigned NOT NULL AUTO_INCREMENT, - `name` VARCHAR(255) NOT NULL, - `id_shop` int(11) unsigned NOT NULL DEFAULT '1', - `id_currency` int(10) unsigned NOT NULL, - `id_country` int(10) unsigned NOT NULL, - `id_group` int(10) unsigned NOT NULL, - `from_quantity` mediumint(8) unsigned NOT NULL, - `price` DECIMAL(20, 6), - `reduction` decimal(20, 6) NOT NULL, + `id_specific_price_rule` int(10) unsigned NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + `id_shop` int(11) unsigned NOT NULL DEFAULT '1', + `id_currency` int(10) unsigned NOT NULL, + `id_country` int(10) unsigned NOT NULL, + `id_group` int(10) unsigned NOT NULL, + `from_quantity` mediumint(8) unsigned NOT NULL, + `price` DECIMAL(20, 6), + `reduction` decimal(20, 6) NOT NULL, `reduction_type` enum('amount', 'percentage') NOT NULL, `from` datetime NOT NULL, `to` datetime NOT NULL, @@ -456,7 +456,7 @@---ALTER TABLE `PREFIX_employee` ADD - `bo_color` varchar(32) default NULL AFTER `stats_date_to`+ `bo_color` varchar(32) default NULL AFTER `stats_date_to`
INSERT INTO `PREFIX_cms_category_lang` VALUES @@ -490,7 +490,7 @@---ALTER TABLE `PREFIX_contact` ADD - `customer_service` tinyint(1) NOT NULL DEFAULT 0 AFTER `email`+ `customer_service` tinyint(1) NOT NULL DEFAULT 0 AFTER `email`
INSERT INTO `PREFIX_specific_price` ( `id_product`, `id_shop`, `id_currency`, @@ -787,12 +787,12 @@---ALTER TABLE `test_modify` MODIFY - `id` INT(11) UNSIGNED NOT NULL;+ `id` INT(11) UNSIGNED NOT NULL;
ALTER TABLE `test_change` CHANGE - `id` `_id` BIGINT(20) UNSIGNED NULL;+ `id` `_id` BIGINT(20) UNSIGNED NULL; ---
SELECT * @@ -952,7 +952,7 @@ a ) AS filtered, CONVERT( - VARCHAR(20), + VARCHAR(20), AVG(SalesYTD) OVER ( PARTITION BY TerritoryID diff --git a/tests/highlight.html b/tests/highlight.html index 6337210..b57624c 100644 --- a/tests/highlight.html +++ b/tests/highlight.html @@ -19,30 +19,30 @@SET NAMES 'utf8';---CREATE TABLE `PREFIX_address` ( - `id_address` int(10) unsigned NOT NULL auto_increment, - `id_country` int(10) unsigned NOT NULL, - `id_state` int(10) unsigned default NULL, - `id_customer` int(10) unsigned NOT NULL default '0', - `id_manufacturer` int(10) unsigned NOT NULL default '0', - `id_supplier` int(10) unsigned NOT NULL default '0', - `id_warehouse` int(10) unsigned NOT NULL default '0', - `alias` varchar(32) NOT NULL, - `company` varchar(64) default NULL, - `lastname` varchar(32) NOT NULL, - `firstname` varchar(32) NOT NULL, - `address1` varchar(128) NOT NULL, - `address2` varchar(128) default NULL, - `postcode` varchar(12) default NULL, - `city` varchar(64) NOT NULL, + `id_address` int(10) unsigned NOT NULL auto_increment, + `id_country` int(10) unsigned NOT NULL, + `id_state` int(10) unsigned default NULL, + `id_customer` int(10) unsigned NOT NULL default '0', + `id_manufacturer` int(10) unsigned NOT NULL default '0', + `id_supplier` int(10) unsigned NOT NULL default '0', + `id_warehouse` int(10) unsigned NOT NULL default '0', + `alias` varchar(32) NOT NULL, + `company` varchar(64) default NULL, + `lastname` varchar(32) NOT NULL, + `firstname` varchar(32) NOT NULL, + `address1` varchar(128) NOT NULL, + `address2` varchar(128) default NULL, + `postcode` varchar(12) default NULL, + `city` varchar(64) NOT NULL, `other` text, - `phone` varchar(16) default NULL, - `phone_mobile` varchar(16) default NULL, - `vat_number` varchar(32) default NULL, - `dni` varchar(16) DEFAULT NULL, + `phone` varchar(16) default NULL, + `phone_mobile` varchar(16) default NULL, + `vat_number` varchar(32) default NULL, + `dni` varchar(16) DEFAULT NULL, `date_add` datetime NOT NULL, `date_upd` datetime NOT NULL, - `active` tinyint(1) unsigned NOT NULL default '1', - `deleted` tinyint(1) unsigned NOT NULL default '0', + `active` tinyint(1) unsigned NOT NULL default '1', + `deleted` tinyint(1) unsigned NOT NULL default '0', PRIMARY KEY (`id_address`), KEY `address_customer` (`id_customer`), KEY `id_country` (`id_country`), @@ -53,51 +53,51 @@ ) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8---CREATE TABLE `PREFIX_alias` ( - `id_alias` int(10) unsigned NOT NULL auto_increment, - `alias` varchar(255) NOT NULL, - `search` varchar(255) NOT NULL, - `active` tinyint(1) NOT NULL default '1', + `id_alias` int(10) unsigned NOT NULL auto_increment, + `alias` varchar(255) NOT NULL, + `search` varchar(255) NOT NULL, + `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`id_alias`), UNIQUE KEY `alias` (`alias`) ) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8---CREATE TABLE `PREFIX_carrier` ( - `id_carrier` int(10) unsigned NOT NULL AUTO_INCREMENT, - `id_reference` int(10) unsigned NOT NULL, - `id_tax_rules_group` int(10) unsigned DEFAULT '0', - `name` varchar(64) NOT NULL, - `url` varchar(255) DEFAULT NULL, - `active` tinyint(1) unsigned NOT NULL DEFAULT '0', - `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0', - `shipping_handling` tinyint(1) unsigned NOT NULL DEFAULT '1', - `range_behavior` tinyint(1) unsigned NOT NULL DEFAULT '0', - `is_module` tinyint(1) unsigned NOT NULL DEFAULT '0', - `is_free` tinyint(1) unsigned NOT NULL DEFAULT '0', - `shipping_external` tinyint(1) unsigned NOT NULL DEFAULT '0', - `need_range` tinyint(1) unsigned NOT NULL DEFAULT '0', - `external_module_name` varchar(64) DEFAULT NULL, - `shipping_method` int(2) NOT NULL DEFAULT '0', - `position` int(10) unsigned NOT NULL default '0', - `max_width` int(10) DEFAULT 0, - `max_height` int(10) DEFAULT 0, - `max_depth` int(10) DEFAULT 0, - `max_weight` int(10) DEFAULT 0, - `grade` int(10) DEFAULT 0, + `id_carrier` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id_reference` int(10) unsigned NOT NULL, + `id_tax_rules_group` int(10) unsigned DEFAULT '0', + `name` varchar(64) NOT NULL, + `url` varchar(255) DEFAULT NULL, + `active` tinyint(1) unsigned NOT NULL DEFAULT '0', + `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0', + `shipping_handling` tinyint(1) unsigned NOT NULL DEFAULT '1', + `range_behavior` tinyint(1) unsigned NOT NULL DEFAULT '0', + `is_module` tinyint(1) unsigned NOT NULL DEFAULT '0', + `is_free` tinyint(1) unsigned NOT NULL DEFAULT '0', + `shipping_external` tinyint(1) unsigned NOT NULL DEFAULT '0', + `need_range` tinyint(1) unsigned NOT NULL DEFAULT '0', + `external_module_name` varchar(64) DEFAULT NULL, + `shipping_method` int(2) NOT NULL DEFAULT '0', + `position` int(10) unsigned NOT NULL default '0', + `max_width` int(10) DEFAULT 0, + `max_height` int(10) DEFAULT 0, + `max_depth` int(10) DEFAULT 0, + `max_weight` int(10) DEFAULT 0, + `grade` int(10) DEFAULT 0, PRIMARY KEY (`id_carrier`), KEY `deleted` (`deleted`,`active`), KEY `id_tax_rules_group` (`id_tax_rules_group`) ) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8---CREATE TABLE IF NOT EXISTS `PREFIX_specific_price_rule` ( - `id_specific_price_rule` int(10) unsigned NOT NULL AUTO_INCREMENT, - `name` VARCHAR(255) NOT NULL, - `id_shop` int(11) unsigned NOT NULL DEFAULT '1', - `id_currency` int(10) unsigned NOT NULL, - `id_country` int(10) unsigned NOT NULL, - `id_group` int(10) unsigned NOT NULL, - `from_quantity` mediumint(8) unsigned NOT NULL, - `price` DECIMAL(20,6), - `reduction` decimal(20,6) NOT NULL, + `id_specific_price_rule` int(10) unsigned NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + `id_shop` int(11) unsigned NOT NULL DEFAULT '1', + `id_currency` int(10) unsigned NOT NULL, + `id_country` int(10) unsigned NOT NULL, + `id_group` int(10) unsigned NOT NULL, + `from_quantity` mediumint(8) unsigned NOT NULL, + `price` DECIMAL(20,6), + `reduction` decimal(20,6) NOT NULL, `reduction_type` enum('amount','percentage') NOT NULL, `from` datetime NOT NULL, `to` datetime NOT NULL, @@ -147,7 +147,7 @@ OR id_hook = (SELECT id_hook FROM `PREFIX_hook` WHERE name = 'displayFooter') AND id_module = (SELECT id_module FROM `PREFIX_module` WHERE name = 'blockreinsurance')--- -ALTER TABLE `PREFIX_employee` ADD `bo_color` varchar(32) default NULL AFTER `stats_date_to`+ALTER TABLE `PREFIX_employee` ADD `bo_color` varchar(32) default NULL AFTER `stats_date_to`---INSERT INTO `PREFIX_cms_category_lang` VALUES(1, 3, 'Inicio', '', 'home', NULL, NULL, NULL)--- @@ -157,7 +157,7 @@ ---ALTER TABLE `PREFIX_customer` ADD `note` text AFTER `secure_key`--- -ALTER TABLE `PREFIX_contact` ADD `customer_service` tinyint(1) NOT NULL DEFAULT 0 AFTER `email`+ALTER TABLE `PREFIX_contact` ADD `customer_service` tinyint(1) NOT NULL DEFAULT 0 AFTER `email`---INSERT INTO `PREFIX_specific_price` (`id_product`, `id_shop`, `id_currency`, `id_country`, `id_group`, `priority`, `price`, `from_quantity`, `reduction`, `reduction_type`, `from`, `to`) ( SELECT dq.`id_product`, 1, 1, 0, 1, 0, 0.00, dq.`quantity`, IF(dq.`id_discount_type` = 2, dq.`value`, dq.`value` / 100), IF (dq.`id_discount_type` = 2, 'amount', 'percentage'), '0000-00-00 00:00:00', '0000-00-00 00:00:00' @@ -247,9 +247,9 @@ ( MyColumn = 1 )) AND ((( SomeOtherColumn = 2);--- -ALTER TABLE `test_modify` MODIFY `id` INT(11) UNSIGNED NOT NULL;+ALTER TABLE `test_modify` MODIFY `id` INT(11) UNSIGNED NOT NULL;--- -ALTER TABLE `test_change` CHANGE `id` `_id` BIGINT(20) UNSIGNED NULL;+ALTER TABLE `test_change` CHANGE `id` `_id` BIGINT(20) UNSIGNED NULL;---SELECT * LIMIT 1; SELECT a,b,c,d FROM e LIMIT 1, 2; SELECT 1,2,3 WHERE a in (1,2,3,4,5) and b=5;--- @@ -295,7 +295,7 @@ GROUP_CONCAT(b, '.') OVER (ORDER BY c GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE GROUP) AS grp, GROUP_CONCAT(b, '.') OVER (ORDER BY c GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE TIES) AS tie, GROUP_CONCAT(b, '.') FILTER (WHERE c != 'two') OVER (ORDER BY a) AS filtered, - CONVERT(VARCHAR(20), AVG(SalesYTD) OVER (PARTITION BY TerritoryID ORDER BY DATEPART(yy, ModifiedDate)), 1) AS MovingAvg, + CONVERT(VARCHAR(20), AVG(SalesYTD) OVER (PARTITION BY TerritoryID ORDER BY DATEPART(yy, ModifiedDate)), 1) AS MovingAvg, AVG(starting_salary) OVER w2 AVG, MIN(starting_salary) OVER w2 MIN_STARTING_SALARY, MAX(starting_salary) OVER (w1 ORDER BY hire_date),