Skip to content

Accept a non-reserved keyword as a table alias without AS - #336

Merged
git-hulk merged 3 commits into
AfterShip:masterfrom
cloudquery:fix/table-keyword-alias-upstream
Oct 28, 2026
Merged

git-hulk merged 3 commits into
AfterShip:masterfrom
cloudquery:fix/table-keyword-alias-upstream

Conversation

@jackcloudquery

@jackcloudquery jackcloudquery commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

SELECT * FROM t ip failed with <EOF> or ';' was expected, but got: "ip": parseTableExpr refused every keyword as a table alias without AS. ClickHouse refuses only the keywords that can follow a table (ParserAlias::restricted_keywords), so FROM t ip, FROM t key and FROM (SELECT 1) ip all run there. Column aliases already work this way since #193.

A keyword after a table is now its alias unless it is:

  • reserved, refused by matchTokenKind as before;
  • one of the non-reserved keywords in ClickHouse's list: ALL, ANTI, ANY, ARRAY, ASOF, FINAL, FULL, GLOBAL, INTERSECT, JOIN, LEFT, RIGHT, SAMPLE, SEMI;
  • LOCAL, which this parser reads only as a join locality (Fix parsing of the GLOBAL/LOCAL join locality and GLOBAL NOT IN #293 rejects FROM t1 LOCAL);
  • COMMENT before a string, which ends a view or table query (... FROM t COMMENT 'x'), as in ClickHouse since Fix parser treating COMMENT as implicit alias in CREATE MATERIALIZED VIEW ClickHouse/ClickHouse#110372;
  • UUID after a table name, which ClickHouse reads as t UUID 'uuid'. FROM (SELECT 1) uuid stays an alias.
  • OVER after a table function, which ClickHouse reads as the function's window clause, so FROM numbers(3) over fails there (checked with clickhouse local 26.9). FROM t over and FROM (SELECT 1) over stay aliases.

Tests:

  • TestNonReservedKeywordAsTableAliasWithoutAs: aliases on tables, subqueries, table functions, joins and comma joins, plus one case for each keyword that can follow a table. Each query is also formatted and parsed back.
  • TestTableAliasWithoutAsForEveryKeyword: every non-reserved keyword after a table name.
  • TestOverAfterTableFunctionIsNotAnAlias: FROM numbers(3) over fails.
  • TestTableAliasRestrictedKeywordsMatchClickHouse: the restricted set must equal the non-reserved part of ClickHouse's list plus LOCAL, so a keyword added later cannot slip past it.
  • New fixture select_table_keyword_alias_without_as.sql, with regenerated output/ and format/ goldens.

Verification:

  • go test -race ./... -compatible passes on Go 1.27; CI covers 1.21.
  • golangci-lint v1.53.3 with .golangci.yml: no issues. govet's atomicalign analyzer was off, because v1.53.3 panics in it when built with Go 1.22.
  • clickhouse local 26.9 (EXPLAIN AST) agrees with every case in the new tests except FROM t LOCAL JOIN u, which ClickHouse reads as alias LOCAL plus a plain join.
  • All 260 keywords after a table name, checked against ClickHouse 26.9: alias or not, the result matches for every non-reserved keyword except LOCAL. The 24 reserved keywords that ClickHouse takes as aliases (SELECT, CASE, ...) stay refused, as before.
  • All 275,425 statements in ClickHouse's tests/queries/0_stateless, parsed with master and with this branch: 27 now parse (implicit aliases such as first, source, user, values and comment), and no statement that parsed before fails or parses differently.

`SELECT * FROM t ip` failed because any keyword after a table was refused
as its alias, while ClickHouse only refuses the keywords that can follow a
table (its ParserAlias::restricted_keywords). Refuse just the non-reserved
ones of those here, plus LOCAL for a LOCAL JOIN, and keep COMMENT before a
string as a view's trailing comment.
ClickHouse reads `t UUID 'uuid'` as a table name with its UUID, so `FROM t uuid`
is a syntax error there while `FROM (SELECT 1) uuid` is an alias; refuse UUID
only after a table name. Test every non-reserved keyword as an implicit table
alias, and check the restricted set against ClickHouse's
ParserAlias::restricted_keywords so the two cannot drift.
Comment thread parser/parser_query.go Resolved
@git-hulk
git-hulk merged commit c6fda50 into AfterShip:master Oct 28, 2026
2 checks passed
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.

2 participants