Fix clickhouse-jdbc: accept WITH RECURSIVE in the JavaCC grammar - #3130
Conversation
The jdbc-v1 grammar had no RECURSIVE token, so RECURSIVE was taken for the name of the first common table expression and the parse was rejected. The query still ran, because the driver sends the original SQL, but every statement creation logged a WARN and the statement was classified as unknown. RECURSIVE is now accepted after WITH and stays usable as an ordinary identifier. Fixes: #3122
Client V2 CoverageCoverage Report
Class Coverage
|
JDBC V2 CoverageCoverage Report
Class Coverage
|
JDBC V1 CoverageCoverage Report
Class Coverage
|
Client V1 CoverageCoverage Report
Class Coverage
|
TriageCategory: Summary What this impacts
Concerns
Required reviewer action
|
|



Description
Fixes #3122 for the legacy driver (
clickhouse-jdbc, jdbc-v1). PR #3128 covers thejdbc-v2grammars; the two modules have separate grammar files, so the change is split per module.clickhouse-jdbc/src/main/javacc/ClickHouseSqlParser.jjhad noRECURSIVEtoken, so inWITH RECURSIVE <name> AS (...)the wordRECURSIVEwas taken for the name of the first common table expression. The following name then had no separating comma, the parse threw, andClickHouseSqlParser.parsefell back to the unparsed statement: the query itself still ran, because the driver sends the original SQL, but everycreateStatement/prepareStatementcall logged aWARNand the statement was classified asUNKNOWN(no statement type, no table).RECURSIVEis now a token, is accepted directly afterWITH, and is listed in both keyword groups so it stays usable as an ordinary identifier.Changes
clickhouse-jdbc/src/main/javacc/ClickHouseSqlParser.jj<RECURSIVE>token, next to<QUOTA>/<REPLACE>;withClause()accepts an optional<RECURSIVE>after<WITH>;RECURSIVEadded toanyKeyword()(identifier positions: column, explicit alias, table, CTE name) and tokeyword()(implicit alias, setting key). Both are needed: without thekeyword()entrySELECT n recursive FROM t— an implicit alias, valid for the server — stops parsing once the word lexes as a keyword.CHANGELOG.md: entry under### Bug Fixesas [jdbc-v1].The server treats
RECURSIVEas reserved in that one position (WITH recursive AS x SELECT xandWITH recursive.x AS y ...areSYNTAX_ERRORon 26.8), so consuming it unconditionally afterWITHmatches the server. Everywhere else the word stays an ordinary identifier, which the tests pin.Test
ClickHouseSqlParserFacadeTest.testRecursiveCte, a TestNG@DataProviderover the parser facade, asserting statement type, database and table:WITH RECURSIVE 1 AS x, a AS (...); a CTE namedrecursive(bare and back-quoted); a recursive CTE in front of theSELECTof anINSERT; a recursive CTE inside a subquery;WITH RECURSIVE FROM tstill yieldsUNKNOWN;WITH t AS (...),WITH 2 AS two), andrecursiveas a column, explicit alias, implicit alias, table name,WITHalias, and setting key.Every expected value was checked against a live ClickHouse 26.8.2 (
EXPLAIN AST) — the rows pin what the server accepts, not what the client used to produce. Five of the new rows fail onmain(UNKNOWNinstead ofSELECT) and pass with the fix.mvn -B -pl clickhouse-jdbc test— 118 tests, 0 failures. No existing test was changed.Pre-PR validation gate
WITH RECURSIVE t AS (...) SELECT sum(n) FROM t→UNKNOWN+WARNonmain)AGENTS.md(targeted module test run,@DataProviderinstead of near-identical methods, no issue numbers in test code, CHANGELOG updated). No public API, nodocs/features.mdchange (jdbc-v1).Note
The issue also asks for consistent logging between parser backends. That is a separate concern from the grammar gap and is not touched here.