From c905f56088a63f88d3c5da6a60bd56cff3d18ac8 Mon Sep 17 00:00:00 2001 From: Nicolas Giraud Date: Mon, 26 Aug 2024 18:21:37 +0200 Subject: [PATCH 1/6] Preparing tests about missing assignment in SET operation. --- tests/Parser/UpdateStatementTest.php | 1 + tests/data/parser/parseUpdateEmptySet.in | 1 + tests/data/parser/parseUpdateEmptySet.out | 176 ++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 tests/data/parser/parseUpdateEmptySet.in create mode 100644 tests/data/parser/parseUpdateEmptySet.out diff --git a/tests/Parser/UpdateStatementTest.php b/tests/Parser/UpdateStatementTest.php index 7f138b28b..7733ce619 100644 --- a/tests/Parser/UpdateStatementTest.php +++ b/tests/Parser/UpdateStatementTest.php @@ -30,6 +30,7 @@ public static function updateProvider(): array ['parser/parseUpdate6'], ['parser/parseUpdate7'], ['parser/parseUpdateErr'], + ['parser/parseUpdateEmptySet'], ]; } } diff --git a/tests/data/parser/parseUpdateEmptySet.in b/tests/data/parser/parseUpdateEmptySet.in new file mode 100644 index 000000000..996d765b5 --- /dev/null +++ b/tests/data/parser/parseUpdateEmptySet.in @@ -0,0 +1 @@ +UPDATE test SET WHERE 1; diff --git a/tests/data/parser/parseUpdateEmptySet.out b/tests/data/parser/parseUpdateEmptySet.out new file mode 100644 index 000000000..ce0632dfb --- /dev/null +++ b/tests/data/parser/parseUpdateEmptySet.out @@ -0,0 +1,176 @@ +{ + "query": "UPDATE test SET WHERE 1;\n", + "lexer": { + "@type": "PhpMyAdmin\\SqlParser\\Lexer", + "str": "UPDATE test SET WHERE 1;\n", + "len": 25, + "last": 25, + "list": { + "@type": "PhpMyAdmin\\SqlParser\\TokensList", + "tokens": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "UPDATE", + "value": "UPDATE", + "keyword": "UPDATE", + "type": 1, + "flags": 3, + "position": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 6 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "test", + "value": "test", + "keyword": null, + "type": 0, + "flags": 0, + "position": 7 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 11 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "SET", + "value": "SET", + "keyword": "SET", + "type": 1, + "flags": 11, + "position": 12 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 15 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "WHERE", + "value": "WHERE", + "keyword": "WHERE", + "type": 1, + "flags": 3, + "position": 16 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 21 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "1", + "value": 1, + "keyword": null, + "type": 6, + "flags": 0, + "position": 22 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": ";", + "value": ";", + "keyword": null, + "type": 9, + "flags": 0, + "position": 23 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "\n", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 24 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": null, + "value": null, + "keyword": null, + "type": 9, + "flags": 0, + "position": null + } + ], + "count": 12, + "idx": 12 + }, + "delimiter": ";", + "delimiterLen": 1, + "strict": false, + "errors": [] + }, + "parser": { + "@type": "PhpMyAdmin\\SqlParser\\Parser", + "list": { + "@type": "@1" + }, + "statements": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Statements\\UpdateStatement", + "tables": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Components\\Expression", + "database": null, + "table": "test", + "column": null, + "expr": "test", + "alias": null, + "function": null, + "subquery": null + } + ], + "set": [], + "where": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Components\\Condition", + "identifiers": [], + "isOperator": false, + "expr": "1" + } + ], + "order": null, + "limit": null, + "join": null, + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": [] + }, + "first": 0, + "last": 8 + } + ], + "brackets": 0, + "strict": false, + "errors": [] + }, + "errors": { + "lexer": [], + "parser": [] + } +} \ No newline at end of file From 688086111672a982de0e0f384e530df87e90a22b Mon Sep 17 00:00:00 2001 From: Nicolas Giraud Date: Mon, 26 Aug 2024 18:23:12 +0200 Subject: [PATCH 2/6] Fix empty SET operations now throw error. --- src/Components/SetOperation.php | 5 +++++ tests/data/parser/parseUpdateEmptySet.out | 10 +++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Components/SetOperation.php b/src/Components/SetOperation.php index 2faf0c611..104f71d9a 100644 --- a/src/Components/SetOperation.php +++ b/src/Components/SetOperation.php @@ -139,6 +139,11 @@ public static function parse(Parser $parser, TokensList $list, array $options = $parser->error('Unexpected token.', $commaLastSeenAt); } + // We got a SET operation without any assignment + if ($ret === []) { + $parser->error('Missing assignment in SET operation.', $list->tokens[$list->idx]); + } + return $ret; } diff --git a/tests/data/parser/parseUpdateEmptySet.out b/tests/data/parser/parseUpdateEmptySet.out index ce0632dfb..dbeff527f 100644 --- a/tests/data/parser/parseUpdateEmptySet.out +++ b/tests/data/parser/parseUpdateEmptySet.out @@ -171,6 +171,14 @@ }, "errors": { "lexer": [], - "parser": [] + "parser": [ + [ + "Missing assignment in SET operation.", + { + "@type": "@7" + }, + 0 + ] + ] } } \ No newline at end of file From 35d8dcf50cce9e1e467c39656677a43a27a73fd9 Mon Sep 17 00:00:00 2001 From: Nicolas Giraud Date: Tue, 27 Aug 2024 13:25:09 +0200 Subject: [PATCH 3/6] Move the check about missing assignment in SET operation to focus UPDATE statements only. --- src/Components/SetOperation.php | 5 ----- src/Statements/UpdateStatement.php | 23 +++++++++++++++++++++++ tests/data/parser/parseUpdate3.out | 7 +++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/Components/SetOperation.php b/src/Components/SetOperation.php index 104f71d9a..2faf0c611 100644 --- a/src/Components/SetOperation.php +++ b/src/Components/SetOperation.php @@ -139,11 +139,6 @@ public static function parse(Parser $parser, TokensList $list, array $options = $parser->error('Unexpected token.', $commaLastSeenAt); } - // We got a SET operation without any assignment - if ($ret === []) { - $parser->error('Missing assignment in SET operation.', $list->tokens[$list->idx]); - } - return $ret; } diff --git a/src/Statements/UpdateStatement.php b/src/Statements/UpdateStatement.php index d6dcdf95c..acbe0b836 100644 --- a/src/Statements/UpdateStatement.php +++ b/src/Statements/UpdateStatement.php @@ -10,7 +10,11 @@ use PhpMyAdmin\SqlParser\Components\Limit; use PhpMyAdmin\SqlParser\Components\OrderKeyword; use PhpMyAdmin\SqlParser\Components\SetOperation; +use PhpMyAdmin\SqlParser\Exceptions\ParserException; +use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statement; +use PhpMyAdmin\SqlParser\Token; +use PhpMyAdmin\SqlParser\TokensList; /** * `UPDATE` statement. @@ -135,4 +139,23 @@ class UpdateStatement extends Statement * @var JoinKeyword[]|null */ public $join; + + /** + * Function called after the token was processed. + * In the update statement, this is used to check that at least one assignment has been set to throw an error if a + * query like `UPDATE acme SET WHERE 1;` is parsed. + * + * @throws ParserException + */ + public function after(Parser $parser, TokensList $list, Token $token) + { + /** @psalm-var string $tokenValue */ + $tokenValue = $token->value; + // Ensure we finished to parse the "SET" token, and if yes, ensure that assignments are defined. + if ($this->set !== [] || (Parser::$KEYWORD_PARSERS[$tokenValue]['field'] ?? null) !== 'set') { + return; + } + + $parser->error('Missing assignment in SET operation.', $list->tokens[$list->idx]); + } } diff --git a/tests/data/parser/parseUpdate3.out b/tests/data/parser/parseUpdate3.out index 33621c291..75a41bffd 100644 --- a/tests/data/parser/parseUpdate3.out +++ b/tests/data/parser/parseUpdate3.out @@ -243,6 +243,13 @@ "@type": "@12" }, 0 + ], + [ + "Missing assignment in SET operation.", + { + "@type": "@11" + }, + 0 ] ] } From b427d0038d3183207398cc50198cc6518078f365 Mon Sep 17 00:00:00 2001 From: Nicolas Giraud Date: Tue, 27 Aug 2024 17:48:13 +0200 Subject: [PATCH 4/6] Improve PHPDoc. --- src/Statements/UpdateStatement.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Statements/UpdateStatement.php b/src/Statements/UpdateStatement.php index acbe0b836..85258e397 100644 --- a/src/Statements/UpdateStatement.php +++ b/src/Statements/UpdateStatement.php @@ -145,7 +145,8 @@ class UpdateStatement extends Statement * In the update statement, this is used to check that at least one assignment has been set to throw an error if a * query like `UPDATE acme SET WHERE 1;` is parsed. * - * @throws ParserException + * @throws ParserException throws the exception, if strict mode is enabled. + * @return void */ public function after(Parser $parser, TokensList $list, Token $token) { From 13747be95a4e632b788668eecc9f964c4f9630c2 Mon Sep 17 00:00:00 2001 From: Nicolas Giraud Date: Tue, 27 Aug 2024 17:55:40 +0200 Subject: [PATCH 5/6] Fix linint issue with PHPDoc. --- src/Statements/UpdateStatement.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Statements/UpdateStatement.php b/src/Statements/UpdateStatement.php index 85258e397..44bd9ff92 100644 --- a/src/Statements/UpdateStatement.php +++ b/src/Statements/UpdateStatement.php @@ -146,6 +146,7 @@ class UpdateStatement extends Statement * query like `UPDATE acme SET WHERE 1;` is parsed. * * @throws ParserException throws the exception, if strict mode is enabled. + * * @return void */ public function after(Parser $parser, TokensList $list, Token $token) From 70784be1d403606fc027e3c716cb697f722cb32e Mon Sep 17 00:00:00 2001 From: Nicolas Giraud Date: Tue, 27 Aug 2024 18:21:56 +0200 Subject: [PATCH 6/6] Fix linint issue with PHPDoc. --- src/Statements/UpdateStatement.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Statements/UpdateStatement.php b/src/Statements/UpdateStatement.php index 44bd9ff92..021e09d5f 100644 --- a/src/Statements/UpdateStatement.php +++ b/src/Statements/UpdateStatement.php @@ -145,9 +145,9 @@ class UpdateStatement extends Statement * In the update statement, this is used to check that at least one assignment has been set to throw an error if a * query like `UPDATE acme SET WHERE 1;` is parsed. * - * @throws ParserException throws the exception, if strict mode is enabled. - * * @return void + * + * @throws ParserException throws the exception, if strict mode is enabled. */ public function after(Parser $parser, TokensList $list, Token $token) {