From 17f58a677815c61e9c75dd35c1ac551ec4c53d35 Mon Sep 17 00:00:00 2001 From: Nicolas Giraud Date: Wed, 9 Apr 2025 18:24:21 +0200 Subject: [PATCH] Fix Window function handling that failed because of "OVER" keyword case-sensitive comparison. --- src/Components/Expression.php | 3 ++- tests/Builder/SelectStatementTest.php | 36 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/Components/Expression.php b/src/Components/Expression.php index a817ebee..8b261a8a 100644 --- a/src/Components/Expression.php +++ b/src/Components/Expression.php @@ -15,6 +15,7 @@ use function is_array; use function rtrim; use function strlen; +use function strtoupper; use function trim; /** @@ -372,7 +373,7 @@ public static function parse(Parser $parser, TokensList $list, array $options = && ! ($prev[1]->flags & Token::FLAG_SYMBOL_VARIABLE) && ! ($prev[1]->flags & Token::FLAG_SYMBOL_PARAMETER)) || ($prev[1]->type === Token::TYPE_NONE - && $prev[1]->token !== 'OVER')) + && strtoupper($prev[1]->token) !== 'OVER')) ) { if (! empty($ret->alias)) { $parser->error('An alias was previously found.', $token); diff --git a/tests/Builder/SelectStatementTest.php b/tests/Builder/SelectStatementTest.php index f90f95b9..49861115 100644 --- a/tests/Builder/SelectStatementTest.php +++ b/tests/Builder/SelectStatementTest.php @@ -414,4 +414,40 @@ public function testBuilderSelectAllFormsOfIndexHints(): void self::assertSame($query, $stmt->build()); } + + public function testBuilderSelectRowNumberOverAlias(): void + { + $query = 'SELECT id, pid, appid, appname, row_number() over (partition by pid, appid) as `group_row_number`' + . ' FROM game group by appname'; + $expected = 'SELECT id, pid, appid, appname, row_number() over (partition by pid, appid) AS `group_row_number`' + . ' FROM game GROUP BY appname'; + + $parser = new Parser($query); + $stmt = $parser->statements[0]; + + self::assertSame($expected, $stmt->build()); + } + + public function testBuilderSelectWindowFunctions(): void + { + $queryVsExpected = [ + 'SELECT row_number() over (ORDER BY NULL) x' => 'SELECT row_number() over (ORDER BY NULL) AS `x`', + 'SELECT rank() over (ORDER BY NULL) x' => 'SELECT rank() over (ORDER BY NULL) AS `x`', + 'SELECT dense_rank() over (ORDER BY NULL) x' => 'SELECT dense_rank() over (ORDER BY NULL) AS `x`', + 'SELECT cume_dist() over (ORDER BY NULL) x' => 'SELECT cume_dist() over (ORDER BY NULL) AS `x`', + 'SELECT ntile(3) over (ORDER BY NULL) x' => 'SELECT ntile(3) over (ORDER BY NULL) AS `x`', + 'SELECT ROW_NUMBER() OVER(ORDER BY NULL) x' => 'SELECT ROW_NUMBER() OVER(ORDER BY NULL) AS `x`', + 'SELECT RANK()OVER(ORDER BY NULL) x' => 'SELECT RANK()OVER(ORDER BY NULL) AS `x`', + 'SELECT DENSE_RANK()OVER(ORDER BY NULL) x' => 'SELECT DENSE_RANK()OVER(ORDER BY NULL) AS `x`', + 'SELECT CUME_DIST()OVER(ORDER BY NULL) x' => 'SELECT CUME_DIST()OVER(ORDER BY NULL) AS `x`', + 'SELECT NTILE(3)OVER(ORDER BY NULL) x' => 'SELECT NTILE(3)OVER(ORDER BY NULL) AS `x`', + ]; + + foreach ($queryVsExpected as $query => $expected) { + $parser = new Parser($query); + $stmt = $parser->statements[0]; + + self::assertSame($expected, $stmt->build()); + } + } }