From 30b5c952f499969501e73ebdef890dd88421c242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Kr=C3=B6g?= Date: Fri, 5 Sep 2025 22:54:42 +0200 Subject: [PATCH 1/2] Add a test for name starting with number followed by _ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maximilian Krög --- tests/Lexer/LexerTest.php | 1 + tests/data/lexer/lexNumberAtStartOfName.in | 1 + tests/data/lexer/lexNumberAtStartOfName.out | 133 ++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 tests/data/lexer/lexNumberAtStartOfName.in create mode 100644 tests/data/lexer/lexNumberAtStartOfName.out diff --git a/tests/Lexer/LexerTest.php b/tests/Lexer/LexerTest.php index e310c94f..02eddf62 100644 --- a/tests/Lexer/LexerTest.php +++ b/tests/Lexer/LexerTest.php @@ -76,6 +76,7 @@ public static function lexProvider(): array ['lexer/lexKeyword'], ['lexer/lexKeyword2'], ['lexer/lexNumber'], + ['lexer/lexNumberAtStartOfName'], ['lexer/lexOperator'], ['lexer/lexOperatorStarIsArithmetic'], ['lexer/lexOperatorStarIsWildcard'], diff --git a/tests/data/lexer/lexNumberAtStartOfName.in b/tests/data/lexer/lexNumberAtStartOfName.in new file mode 100644 index 00000000..f068ab6c --- /dev/null +++ b/tests/data/lexer/lexNumberAtStartOfName.in @@ -0,0 +1 @@ +INSERT INTO 2_bar SELECT 1; \ No newline at end of file diff --git a/tests/data/lexer/lexNumberAtStartOfName.out b/tests/data/lexer/lexNumberAtStartOfName.out new file mode 100644 index 00000000..9dd30ed3 --- /dev/null +++ b/tests/data/lexer/lexNumberAtStartOfName.out @@ -0,0 +1,133 @@ +{ + "query": "INSERT INTO 2_bar SELECT 1;", + "lexer": { + "@type": "PhpMyAdmin\\SqlParser\\Lexer", + "str": "INSERT INTO 2_bar SELECT 1;", + "len": 27, + "last": 27, + "list": { + "@type": "PhpMyAdmin\\SqlParser\\TokensList", + "tokens": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "INSERT", + "value": "INSERT", + "keyword": "INSERT", + "type": 1, + "flags": 35, + "position": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 6 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "INTO", + "value": "INTO", + "keyword": "INTO", + "type": 1, + "flags": 3, + "position": 7 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 11 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "2", + "value": 2, + "keyword": null, + "type": 6, + "flags": 0, + "position": 12 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "_bar", + "value": "_bar", + "keyword": null, + "type": 0, + "flags": 0, + "position": 13 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 17 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "SELECT", + "value": "SELECT", + "keyword": "SELECT", + "type": 1, + "flags": 3, + "position": 18 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 24 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "1", + "value": 1, + "keyword": null, + "type": 6, + "flags": 0, + "position": 25 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": ";", + "value": ";", + "keyword": null, + "type": 9, + "flags": 0, + "position": 26 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": null, + "value": null, + "keyword": null, + "type": 9, + "flags": 0, + "position": null + } + ], + "count": 12, + "idx": 0 + }, + "delimiter": ";", + "delimiterLen": 1, + "strict": false, + "errors": [] + }, + "parser": null, + "errors": { + "lexer": [], + "parser": [] + } +} \ No newline at end of file From b61f7af900f9fb8ca38d5d93885912acedd68cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Kr=C3=B6g?= Date: Fri, 5 Sep 2025 22:57:02 +0200 Subject: [PATCH 2/2] Fix lexing name starting with numner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only [a-zA-z] were considered a separator to the next token, missing were [__git_main]. Signed-off-by: Maximilian Krög --- phpstan-baseline.neon | 2 +- psalm-baseline.xml | 17 +++------ src/Lexer.php | 38 +++++++++------------ tests/data/lexer/lexNumberAtStartOfName.out | 17 +++------ 4 files changed, 26 insertions(+), 48 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index dad26168..147d86f8 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1052,7 +1052,7 @@ parameters: - message: "#^Parameter \\#1 \\$str of static method PhpMyAdmin\\\\SqlParser\\\\Context\\:\\:isSeparator\\(\\) expects string, mixed given\\.$#" - count: 4 + count: 7 path: src/Lexer.php - diff --git a/psalm-baseline.xml b/psalm-baseline.xml index c87d9b3d..2c9351da 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -695,21 +695,14 @@ $this->last $this->last - - $this->str[$this->last + 1] - $this->str[$this->last++] - $this->str[$this->last] - $this->str[$this->last] - $this->str[$this->last] - $this->str[$this->last] - $this->str[$this->last] - $this->str[$this->last] - $this->str[$this->last] - $this->str[$this->last] - $this->str[$this->last] + $this->str[$this->last] $this->str[$this->last] $this->str[$this->last] + + + $this->str[$this->last + 1] + $this->str[$this->last++] $this->str[$this->last] $this->str[$this->last] $this->str[$this->last] diff --git a/src/Lexer.php b/src/Lexer.php index 0e34bc38..a5063dbe 100644 --- a/src/Lexer.php +++ b/src/Lexer.php @@ -842,7 +842,7 @@ public function parseNumber() // or "E" causing wrongly interpreted scientific notation (".e[0 to 9]" is invalid). Such invalid notation could // break the lexer when table names under a given database context starts with ".e[0-9]". // - // Valid final states are: 2, 3, 4 and 6. Any parsing that finished in a + // Valid final states are: 2, 3, 4, 6, and 9. Any parsing that finished in a // state other than these is invalid. // Also, negative states are invalid states. $iBak = $this->last; @@ -886,14 +886,12 @@ public function parseNumber() $state = 4; } elseif ($this->str[$this->last] === 'e' || $this->str[$this->last] === 'E') { $state = 5; - } elseif ( - ($this->str[$this->last] >= 'a' && $this->str[$this->last] <= 'z') - || ($this->str[$this->last] >= 'A' && $this->str[$this->last] <= 'Z') - ) { - // A number can't be directly followed by a letter - $state = -$state; - break; } elseif ($this->str[$this->last] < '0' || $this->str[$this->last] > '9') { + if (! Context::isSeparator($this->str[$this->last])) { + // A number can't be directly followed by a letter _ or $ + $state = -$state; + } + // Just digits and `.`, `e` and `E` are valid characters. break; } @@ -901,14 +899,12 @@ public function parseNumber() $flags |= Token::FLAG_NUMBER_FLOAT; if ($this->str[$this->last] === 'e' || $this->str[$this->last] === 'E') { $state = 5; - } elseif ( - ($this->str[$this->last] >= 'a' && $this->str[$this->last] <= 'z') - || ($this->str[$this->last] >= 'A' && $this->str[$this->last] <= 'Z') - ) { - // A number can't be directly followed by a letter - $state = -$state; - break; } elseif ($this->str[$this->last] < '0' || $this->str[$this->last] > '9') { + if (! Context::isSeparator($this->str[$this->last])) { + // A number can't be directly followed by a letter _ or $ + $state = -$state; + } + // Just digits, `e` and `E` are valid characters. break; } @@ -919,14 +915,12 @@ public function parseNumber() || ($this->str[$this->last] >= '0' && $this->str[$this->last] <= '9') ) { $state = 6; - } elseif ( - ($this->str[$this->last] >= 'a' && $this->str[$this->last] <= 'z') - || ($this->str[$this->last] >= 'A' && $this->str[$this->last] <= 'Z') - ) { - // A number can't be directly followed by a letter - $state = -$state; - break; } else { + if (! Context::isSeparator($this->str[$this->last])) { + // A number can't be directly followed by a letter _ or $ + $state = -$state; + } + break; } } elseif ($state === 6) { diff --git a/tests/data/lexer/lexNumberAtStartOfName.out b/tests/data/lexer/lexNumberAtStartOfName.out index 9dd30ed3..29e6cd3d 100644 --- a/tests/data/lexer/lexNumberAtStartOfName.out +++ b/tests/data/lexer/lexNumberAtStartOfName.out @@ -46,21 +46,12 @@ }, { "@type": "PhpMyAdmin\\SqlParser\\Token", - "token": "2", - "value": 2, - "keyword": null, - "type": 6, - "flags": 0, - "position": 12 - }, - { - "@type": "PhpMyAdmin\\SqlParser\\Token", - "token": "_bar", - "value": "_bar", + "token": "2_bar", + "value": "2_bar", "keyword": null, "type": 0, "flags": 0, - "position": 13 + "position": 12 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -117,7 +108,7 @@ "position": null } ], - "count": 12, + "count": 11, "idx": 0 }, "delimiter": ";",