diff --git a/src/Components/AlterOperation.php b/src/Components/AlterOperation.php index 545d88521..fc358622c 100644 --- a/src/Components/AlterOperation.php +++ b/src/Components/AlterOperation.php @@ -427,25 +427,32 @@ public static function parse(Parser $parser, TokensList $list, array $options = break; } } elseif (! self::checkIfTokenQuotedSymbol($token)) { - if (! empty(Parser::$STATEMENT_PARSERS[$token->value])) { + // If the current token is "SET" or "ENUM", we want to avoid the token between their parenthesis in + // the unknown tokens. + if (in_array($token->value, ['SET', 'ENUM'], true)) { $list->idx++; // Ignore the current token $nextToken = $list->getNext(); - if ($token->value === 'SET' && $nextToken !== null && $nextToken->value === '(') { - // To avoid adding the tokens between the SET() parentheses to the unknown tokens + if ($nextToken !== null && $nextToken->value === '(') { $list->getNextOfTypeAndValue(Token::TYPE_OPERATOR, ')'); - } elseif ($token->value === 'SET' && $nextToken !== null && $nextToken->value === 'DEFAULT') { + } elseif ($nextToken !== null && $nextToken->value === 'DEFAULT') { // to avoid adding the `DEFAULT` token to the unknown tokens. ++$list->idx; } else { - // We have reached the end of ALTER operation and suddenly found - // a start to new statement, but have not find a delimiter between them $parser->error( 'A new statement was found, but no delimiter between it and the previous one.', $token ); break; } + } elseif (! empty(Parser::$statementParsers[$token->value])) { + // We have reached the end of ALTER operation and suddenly found + // a start to new statement, but have not found a delimiter between them + $parser->error( + 'A new statement was found, but no delimiter between it and the previous one.', + $token + ); + break; } elseif ( (array_key_exists($arrayKey, self::$DB_OPTIONS) || array_key_exists($arrayKey, self::$TABLE_OPTIONS)) diff --git a/tests/Parser/AlterStatementTest.php b/tests/Parser/AlterStatementTest.php index 7baeb2fcf..ac21fe110 100644 --- a/tests/Parser/AlterStatementTest.php +++ b/tests/Parser/AlterStatementTest.php @@ -49,6 +49,9 @@ public function alterProvider(): array ['parser/parseAlterTableDropAddIndex1'], ['parser/parseAlterTableDropColumn1'], ['parser/parseAlterTableModifyColumn'], + ['parser/parseAlterTableModifyColumnEnum1'], + ['parser/parseAlterTableModifyColumnEnum2'], + ['parser/parseAlterTableModifyColumnEnum3'], ['parser/parseAlterWithInvisible'], ['parser/parseAlterTableCharacterSet1'], ['parser/parseAlterTableCharacterSet2'], diff --git a/tests/data/parser/parseAlter3.out b/tests/data/parser/parseAlter3.out index b11efe29d..69ae9bef1 100644 --- a/tests/data/parser/parseAlter3.out +++ b/tests/data/parser/parseAlter3.out @@ -554,7 +554,7 @@ "lexer": [], "parser": [ [ - "A new statement was found, but no delimiter between it and the previous one.", + "Missing comma before start of a new alter operation.", { "@type": "@27" }, diff --git a/tests/data/parser/parseAlter9.out b/tests/data/parser/parseAlter9.out index 61cb8f4d0..18f7e0ca5 100644 --- a/tests/data/parser/parseAlter9.out +++ b/tests/data/parser/parseAlter9.out @@ -336,18 +336,6 @@ { "@type": "@16" }, - { - "@type": "@17" - }, - { - "@type": "@18" - }, - { - "@type": "@19" - }, - { - "@type": "@20" - }, { "@type": "@21" }, diff --git a/tests/data/parser/parseAlterTableModifyColumnEnum1.in b/tests/data/parser/parseAlterTableModifyColumnEnum1.in new file mode 100644 index 000000000..59e4cc8c1 --- /dev/null +++ b/tests/data/parser/parseAlterTableModifyColumnEnum1.in @@ -0,0 +1,2 @@ +-- ENUM with a string that is a database option. +ALTER TABLE `test_table` MODIFY `COL` ENUM("COLLATE") NULL; diff --git a/tests/data/parser/parseAlterTableModifyColumnEnum1.out b/tests/data/parser/parseAlterTableModifyColumnEnum1.out new file mode 100644 index 000000000..9feab1a05 --- /dev/null +++ b/tests/data/parser/parseAlterTableModifyColumnEnum1.out @@ -0,0 +1,275 @@ +{ + "query": "-- ENUM with a string that is a database option.\nALTER TABLE `test_table` MODIFY `COL` ENUM(\"COLLATE\") NULL;\n", + "lexer": { + "@type": "PhpMyAdmin\\SqlParser\\Lexer", + "str": "-- ENUM with a string that is a database option.\nALTER TABLE `test_table` MODIFY `COL` ENUM(\"COLLATE\") NULL;\n", + "len": 109, + "last": 109, + "list": { + "@type": "PhpMyAdmin\\SqlParser\\TokensList", + "tokens": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "-- ENUM with a string that is a database option.", + "value": "-- ENUM with a string that is a database option.", + "keyword": null, + "type": 4, + "flags": 4, + "position": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "\n", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 48 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "ALTER", + "value": "ALTER", + "keyword": "ALTER", + "type": 1, + "flags": 3, + "position": 49 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 54 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "TABLE", + "value": "TABLE", + "keyword": "TABLE", + "type": 1, + "flags": 3, + "position": 55 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 60 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "`test_table`", + "value": "test_table", + "keyword": null, + "type": 8, + "flags": 2, + "position": 61 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 73 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "MODIFY", + "value": "MODIFY", + "keyword": "MODIFY", + "type": 1, + "flags": 1, + "position": 74 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 80 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "`COL`", + "value": "COL", + "keyword": null, + "type": 8, + "flags": 2, + "position": 81 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 86 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "ENUM", + "value": "ENUM", + "keyword": "ENUM", + "type": 1, + "flags": 9, + "position": 87 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "(", + "value": "(", + "keyword": null, + "type": 2, + "flags": 16, + "position": 91 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "\"COLLATE\"", + "value": "COLLATE", + "keyword": null, + "type": 7, + "flags": 2, + "position": 92 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": ")", + "value": ")", + "keyword": null, + "type": 2, + "flags": 16, + "position": 101 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 102 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "NULL", + "value": "NULL", + "keyword": "NULL", + "type": 1, + "flags": 3, + "position": 103 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": ";", + "value": ";", + "keyword": null, + "type": 9, + "flags": 0, + "position": 107 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "\n", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 108 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": null, + "value": null, + "keyword": null, + "type": 9, + "flags": 0, + "position": null + } + ], + "count": 21, + "idx": 21 + }, + "delimiter": ";", + "delimiterLen": 1, + "strict": false, + "errors": [] + }, + "parser": { + "@type": "PhpMyAdmin\\SqlParser\\Parser", + "list": { + "@type": "@1" + }, + "statements": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Statements\\AlterStatement", + "table": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\Expression", + "database": null, + "table": "test_table", + "column": null, + "expr": "`test_table`", + "alias": null, + "function": null, + "subquery": null + }, + "altered": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Components\\AlterOperation", + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": { + "1": "MODIFY" + } + }, + "field": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\Expression", + "database": null, + "table": null, + "column": "COL", + "expr": "`COL`", + "alias": null, + "function": null, + "subquery": null + }, + "partitions": null, + "unknown": [ + { + "@type": "@14" + }, + { + "@type": "@19" + } + ] + } + ], + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": { + "3": "TABLE" + } + }, + "first": 0, + "last": 18 + } + ], + "brackets": 0, + "strict": false, + "errors": [] + }, + "errors": { + "lexer": [], + "parser": [] + } +} \ No newline at end of file diff --git a/tests/data/parser/parseAlterTableModifyColumnEnum2.in b/tests/data/parser/parseAlterTableModifyColumnEnum2.in new file mode 100644 index 000000000..af5b1fb30 --- /dev/null +++ b/tests/data/parser/parseAlterTableModifyColumnEnum2.in @@ -0,0 +1,2 @@ +-- ENUM with a string that is a table option. +ALTER TABLE `test_table` MODIFY `COL` ENUM("LOCK") NULL; diff --git a/tests/data/parser/parseAlterTableModifyColumnEnum2.out b/tests/data/parser/parseAlterTableModifyColumnEnum2.out new file mode 100644 index 000000000..3fa5eba6d --- /dev/null +++ b/tests/data/parser/parseAlterTableModifyColumnEnum2.out @@ -0,0 +1,275 @@ +{ + "query": "-- ENUM with a string that is a table option.\nALTER TABLE `test_table` MODIFY `COL` ENUM(\"LOCK\") NULL;\n", + "lexer": { + "@type": "PhpMyAdmin\\SqlParser\\Lexer", + "str": "-- ENUM with a string that is a table option.\nALTER TABLE `test_table` MODIFY `COL` ENUM(\"LOCK\") NULL;\n", + "len": 103, + "last": 103, + "list": { + "@type": "PhpMyAdmin\\SqlParser\\TokensList", + "tokens": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "-- ENUM with a string that is a table option.", + "value": "-- ENUM with a string that is a table option.", + "keyword": null, + "type": 4, + "flags": 4, + "position": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "\n", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 45 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "ALTER", + "value": "ALTER", + "keyword": "ALTER", + "type": 1, + "flags": 3, + "position": 46 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 51 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "TABLE", + "value": "TABLE", + "keyword": "TABLE", + "type": 1, + "flags": 3, + "position": 52 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 57 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "`test_table`", + "value": "test_table", + "keyword": null, + "type": 8, + "flags": 2, + "position": 58 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 70 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "MODIFY", + "value": "MODIFY", + "keyword": "MODIFY", + "type": 1, + "flags": 1, + "position": 71 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 77 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "`COL`", + "value": "COL", + "keyword": null, + "type": 8, + "flags": 2, + "position": 78 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 83 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "ENUM", + "value": "ENUM", + "keyword": "ENUM", + "type": 1, + "flags": 9, + "position": 84 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "(", + "value": "(", + "keyword": null, + "type": 2, + "flags": 16, + "position": 88 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "\"LOCK\"", + "value": "LOCK", + "keyword": null, + "type": 7, + "flags": 2, + "position": 89 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": ")", + "value": ")", + "keyword": null, + "type": 2, + "flags": 16, + "position": 95 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 96 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "NULL", + "value": "NULL", + "keyword": "NULL", + "type": 1, + "flags": 3, + "position": 97 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": ";", + "value": ";", + "keyword": null, + "type": 9, + "flags": 0, + "position": 101 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "\n", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 102 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": null, + "value": null, + "keyword": null, + "type": 9, + "flags": 0, + "position": null + } + ], + "count": 21, + "idx": 21 + }, + "delimiter": ";", + "delimiterLen": 1, + "strict": false, + "errors": [] + }, + "parser": { + "@type": "PhpMyAdmin\\SqlParser\\Parser", + "list": { + "@type": "@1" + }, + "statements": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Statements\\AlterStatement", + "table": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\Expression", + "database": null, + "table": "test_table", + "column": null, + "expr": "`test_table`", + "alias": null, + "function": null, + "subquery": null + }, + "altered": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Components\\AlterOperation", + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": { + "1": "MODIFY" + } + }, + "field": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\Expression", + "database": null, + "table": null, + "column": "COL", + "expr": "`COL`", + "alias": null, + "function": null, + "subquery": null + }, + "partitions": null, + "unknown": [ + { + "@type": "@14" + }, + { + "@type": "@19" + } + ] + } + ], + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": { + "3": "TABLE" + } + }, + "first": 0, + "last": 18 + } + ], + "brackets": 0, + "strict": false, + "errors": [] + }, + "errors": { + "lexer": [], + "parser": [] + } +} \ No newline at end of file diff --git a/tests/data/parser/parseAlterTableModifyColumnEnum3.in b/tests/data/parser/parseAlterTableModifyColumnEnum3.in new file mode 100644 index 000000000..f5e1ca1c5 --- /dev/null +++ b/tests/data/parser/parseAlterTableModifyColumnEnum3.in @@ -0,0 +1,2 @@ +-- ENUM with a string that is a statement. +ALTER TABLE `test_table` MODIFY `COL` ENUM("INSERT") NULL; diff --git a/tests/data/parser/parseAlterTableModifyColumnEnum3.out b/tests/data/parser/parseAlterTableModifyColumnEnum3.out new file mode 100644 index 000000000..f24978a5c --- /dev/null +++ b/tests/data/parser/parseAlterTableModifyColumnEnum3.out @@ -0,0 +1,275 @@ +{ + "query": "-- ENUM with a string that is a statement.\nALTER TABLE `test_table` MODIFY `COL` ENUM(\"INSERT\") NULL;\n", + "lexer": { + "@type": "PhpMyAdmin\\SqlParser\\Lexer", + "str": "-- ENUM with a string that is a statement.\nALTER TABLE `test_table` MODIFY `COL` ENUM(\"INSERT\") NULL;\n", + "len": 102, + "last": 102, + "list": { + "@type": "PhpMyAdmin\\SqlParser\\TokensList", + "tokens": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "-- ENUM with a string that is a statement.", + "value": "-- ENUM with a string that is a statement.", + "keyword": null, + "type": 4, + "flags": 4, + "position": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "\n", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 42 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "ALTER", + "value": "ALTER", + "keyword": "ALTER", + "type": 1, + "flags": 3, + "position": 43 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 48 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "TABLE", + "value": "TABLE", + "keyword": "TABLE", + "type": 1, + "flags": 3, + "position": 49 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 54 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "`test_table`", + "value": "test_table", + "keyword": null, + "type": 8, + "flags": 2, + "position": 55 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 67 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "MODIFY", + "value": "MODIFY", + "keyword": "MODIFY", + "type": 1, + "flags": 1, + "position": 68 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 74 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "`COL`", + "value": "COL", + "keyword": null, + "type": 8, + "flags": 2, + "position": 75 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 80 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "ENUM", + "value": "ENUM", + "keyword": "ENUM", + "type": 1, + "flags": 9, + "position": 81 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "(", + "value": "(", + "keyword": null, + "type": 2, + "flags": 16, + "position": 85 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "\"INSERT\"", + "value": "INSERT", + "keyword": null, + "type": 7, + "flags": 2, + "position": 86 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": ")", + "value": ")", + "keyword": null, + "type": 2, + "flags": 16, + "position": 94 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 95 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "NULL", + "value": "NULL", + "keyword": "NULL", + "type": 1, + "flags": 3, + "position": 96 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": ";", + "value": ";", + "keyword": null, + "type": 9, + "flags": 0, + "position": 100 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "\n", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 101 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": null, + "value": null, + "keyword": null, + "type": 9, + "flags": 0, + "position": null + } + ], + "count": 21, + "idx": 21 + }, + "delimiter": ";", + "delimiterLen": 1, + "strict": false, + "errors": [] + }, + "parser": { + "@type": "PhpMyAdmin\\SqlParser\\Parser", + "list": { + "@type": "@1" + }, + "statements": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Statements\\AlterStatement", + "table": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\Expression", + "database": null, + "table": "test_table", + "column": null, + "expr": "`test_table`", + "alias": null, + "function": null, + "subquery": null + }, + "altered": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Components\\AlterOperation", + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": { + "1": "MODIFY" + } + }, + "field": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\Expression", + "database": null, + "table": null, + "column": "COL", + "expr": "`COL`", + "alias": null, + "function": null, + "subquery": null + }, + "partitions": null, + "unknown": [ + { + "@type": "@14" + }, + { + "@type": "@19" + } + ] + } + ], + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": { + "3": "TABLE" + } + }, + "first": 0, + "last": 18 + } + ], + "brackets": 0, + "strict": false, + "errors": [] + }, + "errors": { + "lexer": [], + "parser": [] + } +} \ No newline at end of file