Skip to content

Accept non-reserved keyword and quoted CTE names (#662) - #667

Open
youdie006 wants to merge 1 commit into
phpmyadmin:masterfrom
youdie006:fix/662-cte-nonreserved-keyword-name
Open

Accept non-reserved keyword and quoted CTE names (#662)#667
youdie006 wants to merge 1 commit into
phpmyadmin:masterfrom
youdie006:fix/662-cte-nonreserved-keyword-name

Conversation

@youdie006

Copy link
Copy Markdown

Fixes #662.

Problem

The WITH (CTE) parser rejects valid CTE names. MySQL accepts a non-reserved keyword (e.g. data, text) as an unquoted identifier, and any identifier when backtick-quoted, but the parser reports The name of the CTE was expected. for:

WITH data AS (SELECT 1) SELECT * FROM data

The same happens for a backtick-quoted name such as WITH \my_cte` AS (...)`.

Root cause

In WithStatement::parse() the CTE-name state only accepts a token of type TokenType::None. A non-reserved keyword is lexed as TokenType::Keyword (without FLAG_KEYWORD_RESERVED), and a backtick-quoted identifier as TokenType::Symbol (with FLAG_SYMBOL_BACKTICK), so both fail the guard and are reported as errors.

Fix

Also accept a non-reserved keyword and a backtick-quoted symbol as the CTE name. Token::$value already carries the correct name (backticks stripped for the symbol case, the keyword text for the keyword case), so the rest of the method is unchanged. Reserved keywords (e.g. SELECT) are still rejected.

The old condition negated preg_match() (int|false), suppressed by a PHPStan baseline entry; the new condition compares explicitly (=== 1), so I removed the now-obsolete baseline entry.

Test

Added testWithNonReservedOrQuotedName (data provider) to tests/Parser/WithStatementTest.php, covering a non-reserved keyword name, a backtick-quoted keyword name, and a backtick-quoted identifier with a space. Red-green verified: before the fix all three produce The name of the CTE was expected.; after, each parses with zero errors and the expected wither name.

Verified locally under PHP 8.4: full phpunit (1023 tests), phpcs and psalm clean. phpstan reports only one pre-existing error in CreateStatement.php that is also present on the unmodified tree (a baseline/PHP-version artifact unrelated to this change).


Disclosure: prepared with AI assistance (Claude); I reviewed it and verified the red-green test and the project test/analysis gates.

The WITH parser only accepted a CTE name tokenized as TokenType::None,
so a non-reserved keyword (e.g. data) or a backtick-quoted identifier
(e.g. my_cte) was rejected with "The name of the CTE was expected."
even though MySQL accepts both, making valid CTE queries fail to parse.

Accept, in addition to a plain identifier, a non-reserved keyword and a
backtick-quoted symbol as the CTE name; Token::value already yields the
correct name (backticks stripped) in every case.

Also removed the now-obsolete negated-boolean phpstan baseline entry
that covered the replaced "! preg_match(...)" expression.

Fixes phpmyadmin#662
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CTE parsing fails when name is a non-reserved keyword

1 participant