Skip to content

bug: create-table parser does not track backtick identifiers, silently dropping projections on tables with parens in a column name #196

Description

@alvarogar4

Bug Description

extractCreateTableBody walks create_table_query counting parenthesis depth and skips over ' and " string literals — but it does not track backtick-quoted identifiers:

if (char === "'" || char === '"') {
  inString = true
  stringQuote = char
  continue
}

A backtick-quoted column name containing a parenthesis (ClickHouse permits this) therefore decrements the depth counter mid-identifier, the column-list body is truncated at the wrong offset, and everything derived from that body is silently lost.

Reproduction

const query = `CREATE TABLE app.t (
  a String,
  \`weird)name\` String,
  PROJECTION p INDEX a TYPE basic
)
ENGINE = MergeTree
ORDER BY a`

parseProjectionsFromCreateTableQuery(query)   // => []   (expected: the `p` projection)

The projection itself is entirely ordinary — INDEX a TYPE basic. It is the unrelated `weird)name` column that breaks the parse, so a single such column costs the table all of its projections.

Impact

Low in practice: it requires a column whose backtick-quoted name contains ( or ), which is rare. Filing for the record because the failure is silent — chkit pull emits a table with no projections field and no warning, exactly the shape of #183, and drift then reports the live projection as an extra object.

parseClauseFromCreateTableQuery shares the same file and the same blind spot, so partitionBy / ttl / key clauses are exposed to the same truncation.

Investigation Notes

  • packages/clickhouse/src/create-table-parser.tsextractCreateTableBody tracks ' and " only.
  • splitTopLevelComma (packages/core/src/key-clause.ts) does track backticks, and stripWrappingParens (packages/core/src/projection.ts, added in PR fix(pull): capture index-only projections and render them correctly #193) was made to match it. extractCreateTableBody is now the odd one out.

Verified against ClickHouse 26.3.9.1 — a backtick identifier containing ) is accepted and round-trips:

PROJECTION p INDEX `weird)name` TYPE basic

so chkit is the only layer that mishandles it.

Expected Behavior

A backtick-quoted identifier is opaque text to the parser: parens inside it are not nesting.

Proposed Fix

Track ` alongside ' and " in extractCreateTableBody (and in parseClauseFromCreateTableQuery), matching the quote handling already in splitTopLevelComma. Better still, factor the three copies of quote-aware scanning into one shared helper — see also #195.

May share a root-cause family with #190, where engine parameters bleed into the parsed primaryKey/orderBy; worth checking whether one hardening pass fixes both.

Verification

  • Unit in packages/clickhouse/src/index.test.ts: the CREATE TABLE above yields [{ name: 'p', index: 'a', type: 'basic' }].
  • Also assert a backtick identifier inside the projection's own index expression: PROJECTION p INDEX (`weird)name`) TYPE basic{ index: '`weird)name`' } (core already normalizes this correctly).

Found while verifying #183 / PR #193.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions