Skip to content

Allow reserved keywords as bare column names in SELECT list#269

Merged
git-hulk merged 2 commits into
AfterShip:masterfrom
erezrokah:fix/keyword-as-column-in-select
May 12, 2026
Merged

Allow reserved keywords as bare column names in SELECT list#269
git-hulk merged 2 commits into
AfterShip:masterfrom
erezrokah:fix/keyword-as-column-in-select

Conversation

@erezrokah
Copy link
Copy Markdown
Contributor

@erezrokah erezrokah commented May 11, 2026

ClickHouse server accepts essentially every reserved keyword as a bare column reference in a SELECT projection; the parser previously rejected most of them. This widens isSelectItemTerminatorKeyword and parseColumnExpr to parse a keyword as an identifier when the next token is ,, AS, or another clause-starter keyword — none of which can legally follow a real clause/expression starter.

Validated against ClickHouse 25.10.7.6: 255/256 reserved keywords now parse as bare column refs (only NOT rejected — a unary operator, also rejected by CH).

Backticked identifiers tokenize as TokenKindIdent, so PR #268's trailing-comma handling is preserved (regression fixture select_trailing_comma_before_from_keyword_table.sql).

ch-demo.mp4

Test plan

Copilot AI review requested due to automatic review settings May 11, 2026 11:41
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the SELECT-list parsing logic to accept clause-starter keywords (e.g., LIMIT) as bare column names in projections when they’re clearly not starting a real clause, aligning behavior with ClickHouse for queries like SELECT ..., limit, ... FROM t.

Changes:

  • Adds lookahead-based disambiguation in isSelectItemTerminatorKeyword to avoid prematurely ending parseSelectItems when encountering keywords like LIMIT used as identifiers.
  • Introduces a new query fixture and corresponding golden/format/beautify outputs covering limit as an unquoted column name.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
parser/parser_column.go Adds keyword lookahead logic to disambiguate SELECT item terminators vs identifier-like keywords.
parser/testdata/query/select_limit_as_column.sql New repro fixture for limit used as a column in SELECT list.
parser/testdata/query/output/select_limit_as_column.sql.golden.json Golden AST output for the new fixture.
parser/testdata/query/format/select_limit_as_column.sql Formatter expected output for the new fixture.
parser/testdata/query/format/beautify/select_limit_as_column.sql Beautifier expected output for the new fixture.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread parser/parser_column.go Outdated
@erezrokah erezrokah marked this pull request as draft May 11, 2026 11:46
@erezrokah erezrokah requested a review from Copilot May 11, 2026 11:53
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Comment thread parser/parser_column.go Outdated
@erezrokah erezrokah changed the title fix: Allow LIMIT/OFFSET/FORMAT as column names in SELECT list fix: Allow reserved keywords as bare column names in SELECT list May 11, 2026
@erezrokah erezrokah requested a review from Copilot May 11, 2026 13:28
@erezrokah erezrokah marked this pull request as ready for review May 11, 2026 13:29
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@erezrokah erezrokah force-pushed the fix/keyword-as-column-in-select branch from 28d0efc to 5a5bcf3 Compare May 11, 2026 13:35
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 1 comment.

Comment thread parser/parser_column.go
Extend keyword-as-identifier handling to recognize end-of-statement
(EOF or `;`) as a disambiguator in expression position, so projections
like `SELECT case`, `SELECT case;`, or `SELECT limit` parse as bare
column refs — matching ClickHouse server (verified against 25.10.7.6,
which returns UNKNOWN_IDENTIFIER, i.e. syntactic accept).

The eos check is applied inline in parseColumnExpr rather than added to
keywordIsSelectItemIdentifier, because the latter is shared with the
terminator/alias-position check, where a trailing clause-starter
keyword at EOF (e.g. `SELECT * FROM`) must still be treated as a
terminator. Verified `SELECT * FROM` still errors as before.

Fixtures:
- select_keyword_as_only_column.sql        (`SELECT interval`)
- select_keyword_as_only_column_semicolon  (`SELECT case;`)
- select_clause_keyword_as_only_column     (`SELECT limit`)
- select_keyword_as_alias                  (`SELECT 1 AS interval, 2 AS from, 3 AS limit`)

The AS-alias fixture documents that `SELECT 1 AS <reserved-kw>` already
works for every reserved keyword without special handling, because
matchTokenKind(TokenKindIdent) coerces TokenKindKeyword and so
parseIdent accepts keyword tokens as alias names; added a comment at
the AS branch of parseSelectItem to make that intentional.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 37 out of 37 changed files in this pull request and generated 1 comment.

Comment thread parser/parser_column.go
@erezrokah
Copy link
Copy Markdown
Contributor Author

@git-hulk this should be good to review now

@git-hulk
Copy link
Copy Markdown
Member

@git-hulk this should be good to review now

@erezrokah Thank you!

@git-hulk git-hulk self-requested a review May 12, 2026 02:29
@git-hulk git-hulk changed the title fix: Allow reserved keywords as bare column names in SELECT list Allow reserved keywords as bare column names in SELECT list May 12, 2026
@git-hulk git-hulk merged commit 33c6bf2 into AfterShip:master May 12, 2026
4 of 5 checks passed
orian pushed a commit to orian/clickhouse-sql-parser that referenced this pull request May 13, 2026
…p#269)

Extend keyword-as-identifier handling to recognize end-of-statement
(EOF or `;`) as a disambiguator in expression position, so projections
like `SELECT case`, `SELECT case;`, or `SELECT limit` parse as bare
column refs — matching ClickHouse server (verified against 25.10.7.6,
which returns UNKNOWN_IDENTIFIER, i.e. syntactic accept).

The eos check is applied inline in parseColumnExpr rather than added to
keywordIsSelectItemIdentifier, because the latter is shared with the
terminator/alias-position check, where a trailing clause-starter
keyword at EOF (e.g. `SELECT * FROM`) must still be treated as a
terminator. Verified `SELECT * FROM` still errors as before.

Fixtures:
- select_keyword_as_only_column.sql        (`SELECT interval`)
- select_keyword_as_only_column_semicolon  (`SELECT case;`)
- select_clause_keyword_as_only_column     (`SELECT limit`)
- select_keyword_as_alias                  (`SELECT 1 AS interval, 2 AS from, 3 AS limit`)

The AS-alias fixture documents that `SELECT 1 AS <reserved-kw>` already
works for every reserved keyword without special handling, because
matchTokenKind(TokenKindIdent) coerces TokenKindKeyword and so
parseIdent accepts keyword tokens as alias names; added a comment at
the AS branch of parseSelectItem to make that intentional.
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.

3 participants