From a19a0a556d124a8ba67ad9b9ec8f3297bdc26ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sat, 18 May 2024 10:50:31 +0200 Subject: [PATCH 1/5] Add "reserved" words from top level/new line lists Minimize diff for next commits, non functional change. --- src/Tokenizer.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/Tokenizer.php b/src/Tokenizer.php index 2ac597d..6f6e9aa 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', @@ -46,6 +48,7 @@ final class Tokenizer 'BETWEEN', 'BINLOG', 'BOTH', + 'BY', 'CASCADE', 'CASE', 'CHANGE', @@ -87,6 +90,7 @@ final class Tokenizer 'DISTINCTROW', 'DIV', 'DO', + 'DROP', 'DUMPFILE', 'DUPLICATE', 'DYNAMIC', @@ -99,6 +103,8 @@ final class Tokenizer 'ESCAPE', 'ESCAPED', 'EVENTS', + 'EXCEPT', + 'EXCLUDE', 'EXEC', 'EXECUTE', 'EXISTS', @@ -115,6 +121,7 @@ final class Tokenizer 'FOR', 'FORCE', 'FOREIGN', + 'FROM', 'FULL', 'FULLTEXT', 'FUNCTION', @@ -123,6 +130,7 @@ final class Tokenizer 'GRANTS', 'GROUP', 'GROUPS', + 'HAVING', 'HEAP', 'HIGH_PRIORITY', 'HOSTS', @@ -137,21 +145,26 @@ final class Tokenizer 'INDEX', 'INDEXES', 'INFILE', + 'INNER', 'INSERT', 'INSERT_ID', 'INSERT_METHOD', + 'INTERSECT', 'INTERVAL', 'INTO', 'INVOKER', 'IS', 'ISOLATION', + 'JOIN', 'KEY', 'KEYS', 'KILL', 'LAST_INSERT_ID', 'LEADING', + 'LEFT', 'LEVEL', 'LIKE', + 'LIMIT', 'LINEAR', 'LINES', 'LOAD', @@ -177,6 +190,7 @@ final class Tokenizer 'MINUTE_SECOND', 'MIN_ROWS', 'MODE', + 'MODIFY', 'MONTH', 'MRG_MYISAM', 'MYISAM', @@ -190,6 +204,9 @@ final class Tokenizer 'OPTIMIZE', 'OPTION', 'OPTIONALLY', + 'OR', + 'ORDER', + 'OUTER', 'OUTFILE', 'OVER', 'PACK_KEYS', @@ -229,6 +246,7 @@ final class Tokenizer 'RETURN', 'RETURNS', 'REVOKE', + 'RIGHT', 'RLIKE', 'ROLLBACK', 'ROW', @@ -236,6 +254,7 @@ final class Tokenizer 'ROW_FORMAT', 'SECOND', 'SECURITY', + 'SELECT', 'SEPARATOR', 'SERIALIZABLE', 'SESSION', @@ -290,18 +309,24 @@ final class Tokenizer 'TYPES', 'UNBOUNDED', 'UNCOMMITTED', + 'UNION', 'UNIQUE', 'UNLOCK', 'UNSIGNED', + 'UPDATE', 'USAGE', 'USE', 'USING', + 'VALUES', 'VARIABLES', 'VIEW', 'WHEN', + 'WHERE', + 'WINDOW', 'WITH', 'WORK', 'WRITE', + 'XOR', 'YEAR_MONTH', ]; From 5219b1773b1cb6d9e78226b13fa88ea72a90a3c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sun, 2 Jun 2024 18:48:52 +0200 Subject: [PATCH 2/5] Improve assertion for "function" keyword list Functions are always case insensitive and cannot contain a whitespace. --- tests/TokenizerTest.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/TokenizerTest.php b/tests/TokenizerTest.php index f8a767e..18a820e 100644 --- a/tests/TokenizerTest.php +++ b/tests/TokenizerTest.php @@ -13,6 +13,8 @@ use ReflectionClass; use function array_filter; +use function array_merge; +use function array_unique; use function implode; use function preg_match; use function serialize; @@ -52,11 +54,14 @@ 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; }); From 82e01b2896a650bd3365cbba33aed5c50c30e9ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sun, 2 Jun 2024 18:53:00 +0200 Subject: [PATCH 3/5] Assert "function" keyword is not "reserved" "reserved" keyword is tokenized sooner thus the same keyword defined as "function" is useless. --- src/Tokenizer.php | 22 ---------------------- tests/TokenizerTest.php | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/src/Tokenizer.php b/src/Tokenizer.php index 6f6e9aa..ed20a66 100644 --- a/src/Tokenizer.php +++ b/src/Tokenizer.php @@ -416,19 +416,15 @@ final class Tokenizer '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', @@ -441,23 +437,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', @@ -505,17 +497,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', @@ -525,12 +512,10 @@ final class Tokenizer 'IS_USED_LOCK', 'LAG', 'LAST_DAY', - 'LAST_INSERT_ID', 'LAST_VALUE', 'LCASE', 'LEAD', 'LEAST', - 'LEFT', 'LENGTH', 'LINEFROMTEXT', 'LINEFROMWKB', @@ -565,11 +550,9 @@ final class Tokenizer 'MICROSECOND', 'MID', 'MIN', - 'MINUTE', 'MLINEFROMTEXT', 'MLINEFROMWKB', 'MOD', - 'MONTH', 'MONTHNAME', 'MPOINTFROMTEXT', 'MPOINTFROMWKB', @@ -597,7 +580,6 @@ final class Tokenizer 'OLD_PASSWORD', 'ORD', 'OVERLAPS', - 'PASSWORD', 'PERCENTILE_CONT', 'PERCENTILE_DISC', 'PERCENT_RANK', @@ -625,16 +607,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', @@ -676,7 +655,6 @@ final class Tokenizer 'TOUCHES', 'TO_DAYS', 'TRIM', - 'TRUNCATE', 'UCASE', 'UNCOMPRESS', 'UNCOMPRESSED_LENGTH', diff --git a/tests/TokenizerTest.php b/tests/TokenizerTest.php index 18a820e..3e737a9 100644 --- a/tests/TokenizerTest.php +++ b/tests/TokenizerTest.php @@ -12,6 +12,7 @@ use PHPUnit\Framework\TestCase; use ReflectionClass; +use function array_diff_key; use function array_filter; use function array_merge; use function array_unique; @@ -68,6 +69,19 @@ public function testKeywordsAreSingleUpperWord(): void 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)), + ); + } + /** @param list $expectedTokens */ public static function assertEqualsTokens(array $expectedTokens, Cursor $cursor): void { From 0f7b39d5a472257b2ce4d40f6d5cc8f1e598b846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sun, 2 Jun 2024 18:57:33 +0200 Subject: [PATCH 4/5] Add all "type reserved" MySQL keywords To fix all type highlighting in function tests. --- src/Tokenizer.php | 33 +++++++++- tests/SqlFormatterTest.php | 2 +- tests/TokenizerTest.php | 2 +- tests/clihighlight.txt | 120 ++++++++++++++++++------------------ tests/format-highlight.html | 120 ++++++++++++++++++------------------ tests/highlight.html | 120 ++++++++++++++++++------------------ 6 files changed, 214 insertions(+), 183 deletions(-) diff --git a/src/Tokenizer.php b/src/Tokenizer.php index ed20a66..35701d8 100644 --- a/src/Tokenizer.php +++ b/src/Tokenizer.php @@ -46,13 +46,17 @@ final class Tokenizer 'BACKUP', 'BEGIN', 'BETWEEN', + 'BIGINT', + 'BINARY', 'BINLOG', + 'BLOB', 'BOTH', 'BY', 'CASCADE', 'CASE', 'CHANGE', 'CHANGED', + 'CHAR', 'CHARACTER', 'CHARSET', 'CHECK', @@ -79,6 +83,7 @@ final class Tokenizer 'DAY_HOUR', 'DAY_MINUTE', 'DAY_SECOND', + 'DECIMAL', 'DEFAULT', 'DEFINER', 'DELAYED', @@ -90,6 +95,7 @@ final class Tokenizer 'DISTINCTROW', 'DIV', 'DO', + 'DOUBLE', 'DROP', 'DUMPFILE', 'DUPLICATE', @@ -110,12 +116,16 @@ final class Tokenizer 'EXISTS', 'EXPLAIN', 'EXTENDED', + 'FALSE', 'FAST', 'FIELDS', 'FILE', 'FILTER', 'FIRST', 'FIXED', + 'FLOAT', + 'FLOAT4', + 'FLOAT8', 'FLUSH', 'FOLLOWING', 'FOR', @@ -149,6 +159,13 @@ final class Tokenizer 'INSERT', 'INSERT_ID', 'INSERT_METHOD', + 'INT', + 'INT1', + 'INT2', + 'INT3', + 'INT4', + 'INT8', + 'INTEGER', 'INTERSECT', 'INTERVAL', 'INTO', @@ -172,6 +189,9 @@ final class Tokenizer 'LOCK', 'LOCKS', 'LOGS', + 'LONG', + 'LONGBLOB', + 'LONGTEXT', 'LOW_PRIORITY', 'MARIA', 'MASTER', @@ -185,6 +205,9 @@ final class Tokenizer 'MAX_UPDATES_PER_HOUR', 'MAX_USER_CONNECTIONS', 'MEDIUM', + 'MEDIUMBLOB', + 'MEDIUMINT', + 'MEDIUMTEXT', 'MERGE', 'MINUTE', 'MINUTE_SECOND', @@ -198,6 +221,7 @@ final class Tokenizer 'NATURAL', 'NOT', 'NULL', + 'NUMERIC', 'OFFSET', 'ON', 'OPEN', @@ -231,6 +255,7 @@ final class Tokenizer 'READ', 'READ_ONLY', 'READ_WRITE', + 'REAL', 'RECURSIVE', 'REFERENCES', 'REGEXP', @@ -263,6 +288,7 @@ final class Tokenizer 'SHOW', 'SHUTDOWN', 'SLAVE', + 'SMALLINT', 'SONAME', 'SOUNDS', 'SQL', @@ -300,6 +326,9 @@ final class Tokenizer 'TERMINATED', 'THEN', 'TIES', + 'TINYBLOB', + 'TINYINT', + 'TINYTEXT', 'TO', 'TRAILING', 'TRANSACTIONAL', @@ -318,6 +347,9 @@ final class Tokenizer 'USE', 'USING', 'VALUES', + 'VARBINARY', + 'VARCHAR', + 'VARCHARACTER', 'VARIABLES', 'VIEW', 'WHEN', @@ -414,7 +446,6 @@ final class Tokenizer 'CEIL', 'CEILING', 'CENTROID', - 'CHAR', 'CHARACTER_LENGTH', 'CHAR_LENGTH', 'CHECKSUM_AGG', 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 3e737a9..ce421c3 100644 --- a/tests/TokenizerTest.php +++ b/tests/TokenizerTest.php @@ -190,7 +190,7 @@ public static function tokenizeLongConcatData(): Generator $expectedTokens[] = new Token(Token::TOKEN_TYPE_WHITESPACE, ' '); $expectedTokens[] = new Token(Token::TOKEN_TYPE_RESERVED, 'as'); $expectedTokens[] = new Token(Token::TOKEN_TYPE_WHITESPACE, ' '); - $expectedTokens[] = new Token(Token::TOKEN_TYPE_WORD, 'blob'); + $expectedTokens[] = new Token(Token::TOKEN_TYPE_RESERVED, 'blob'); $expectedTokens[] = new Token(Token::TOKEN_TYPE_BOUNDARY, ')'); } diff --git a/tests/clihighlight.txt b/tests/clihighlight.txt index 4d4386c..32e74cb 100644 --- a/tests/clihighlight.txt +++ b/tests/clihighlight.txt @@ -46,30 +46,30 @@ 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`), @@ -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/format-highlight.html b/tests/format-highlight.html index 7c9b1d9..358b86b 100644 --- a/tests/format-highlight.html +++ b/tests/format-highlight.html @@ -46,30 +46,30 @@ 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`),
@@ -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), From 1c0187f139e7797d8b54ba3f8c13928475193996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sun, 2 Jun 2024 19:48:32 +0200 Subject: [PATCH 5/5] Add exact reserved keyword lists into TokenizerTest For future compilation of Tokenizer lists. Also test if all intersected keywords are really reserved. --- tests/TokenizerTest.php | 1513 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1513 insertions(+) diff --git a/tests/TokenizerTest.php b/tests/TokenizerTest.php index ce421c3..d522ff1 100644 --- a/tests/TokenizerTest.php +++ b/tests/TokenizerTest.php @@ -12,8 +12,10 @@ 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; @@ -24,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 * @@ -46,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; @@ -82,6 +1577,24 @@ public function testKeywordsAreDisjunctive(): void ); } + 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 list $expectedTokens */ public static function assertEqualsTokens(array $expectedTokens, Cursor $cursor): void {