Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions src/Statements/WithStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,34 @@ public function parse(Parser $parser, TokensList $list): void
// Length of expression tokens is null by default, in order for the $subList to start
// from $list->idx to the end of the $list.
$lengthOfExpressionTokens = null;
$idxOfDelimiter = null;

// Keep a terminal delimiter in the subparser, but stop before a delimiter
// that separates this CTE expression from another statement.
if ($list->getNextOfType(TokenType::Delimiter)) {
$delimiterIndex = $list->idx - 1;
$nextToken = $list->getNext();
if ($nextToken !== null && $nextToken->token !== '') {
$idxOfDelimiter = $delimiterIndex;
$idxOfLastParsedToken = $idxOfDelimiter + 1;
$lengthOfExpressionTokens = $idxOfDelimiter - $idxBeforeSearch;
}
}

$list->idx = $idxBeforeSearch;

$idxOfOn = null;
$searchEnd = $idxOfDelimiter ?? $list->count;
for ($i = $idxBeforeSearch; $i < $searchEnd; ++$i) {
$candidate = $list->tokens[$i];
if ($candidate->type === TokenType::Keyword && $candidate->keyword === 'ON') {
$idxOfOn = $i;
$list->idx = $idxOfOn + 1;
break;
}
}

if ($list->getNextOfTypeAndValue(TokenType::Keyword, 'ON')) {
// (-1) because getNextOfTypeAndValue returned ON and increased the index.
$idxOfOn = $list->idx - 1;
if ($idxOfOn !== null) {
// We want to make sure that it's `ON DUPLICATE KEY UPDATE`
$dubplicateToken = $list->getNext();
$keyToken = $list->getNext();
Expand All @@ -228,7 +252,7 @@ public function parse(Parser $parser, TokensList $list): void
) {
// Index of the last parsed token will be the token before the ON Keyword
$idxOfLastParsedToken = $idxOfOn - 1;
// The length of the expression tokens would be the difference
// The length of expression tokens would be the difference
// between the first unrelated token `ON` and the idx
// before skipping the CTE tokens.
$lengthOfExpressionTokens = $idxOfOn - $idxBeforeSearch;
Expand Down
26 changes: 26 additions & 0 deletions tests/Parser/CreateStatementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace PhpMyAdmin\SqlParser\Tests\Parser;

use PhpMyAdmin\SqlParser\Parser;
use PhpMyAdmin\SqlParser\Tests\TestCase;
use PHPUnit\Framework\Attributes\DataProvider;

Expand Down Expand Up @@ -82,4 +83,29 @@ public static function createProvider(): array
['parser/parseCreateOrReplaceView1'],
];
}

public function testCreateViewsWithCteRemainSeparate(): void
{
$sql = <<<'SQL'
CREATE VIEW view1 AS
WITH foo AS (SELECT 1 AS id)
SELECT * FROM foo;
CREATE VIEW view2 AS
WITH bar AS (SELECT 2 AS id)
SELECT * FROM bar;
SQL;

$parser = new Parser($sql);

self::assertSame([], $this->getErrorsAsArray($parser));
self::assertCount(2, $parser->statements);
self::assertSame(
'CREATE VIEW view1 AS WITH foo AS (SELECT 1 AS `id`) SELECT * FROM foo ',
$parser->statements[0]->build(),
);
self::assertSame(
'CREATE VIEW view2 AS WITH bar AS (SELECT 2 AS `id`) SELECT * FROM bar ',
$parser->statements[1]->build(),
);
}
}
Loading