Skip to content

fix(test-runner): split $$ heredocs and escaped backticks in splitQueries() - #1097

Open
Tyagiquamar wants to merge 1 commit into
ClickHouse:mainfrom
Tyagiquamar:fix/1096-split-queries-heredoc-backtick
Open

Tyagiquamar wants to merge 1 commit into
ClickHouse:mainfrom
Tyagiquamar:fix/1096-split-queries-heredoc-backtick

Conversation

@Tyagiquamar

Copy link
Copy Markdown

Fixes #1096.

Summary

splitQueries() in the upstream SQL test harness only tracked ', " and backticks, backslash escapes outside backticks, and the two comment styles. The server lexer also has dollar quoting and honors backslash escapes inside quoted identifiers, so two constructs were mis-split:

  • $$ ... $$ / $tag$ ... $tag$ heredocs (7 upstream files). A ' or " inside the heredoc toggled the splitter's quote state, so the remaining statements were merged into one, and a ; inside the heredoc could split it. Example: 03011_definitive_guide_to_cast was seen as 82 statements instead of 91, 04038_ascii_cjk_tokenizer as 28 instead of 43.
  • A backslash-escaped backtick inside a quoted identifier (1 upstream file). `a\`b` closed the identifier early, leaving it open and merging the rest of the file: 04097_tuple_inside_nullable_subcolumn_descendants was seen as 15 statements instead of 18.

Root Cause

src/split-queries.ts hand-scans the SQL with three quote flags and no notion of dollar quoting. It also only entered the escape handling for ' and " (if ((inSingleQuote || inDoubleQuote) && ch === "\\")), while the server lexer's quotedString<>() treats ', " and ` identically. There is no bug in ClickHouse; this is purely the harness's statement splitter disagreeing with src/Parsers/Lexer.cpp about where a statement ends.

Technical Solution

Kept the hand-written scanner (the issue's measurement does not justify adopting the lexer, and 17 upstream files use syntax the lexer rejects) and taught it the two missing rules, mirroring the lexer:

  • findHeredocEnd() implements the lexer's $ branch: an opening $, an optional tag of word characters ([A-Za-z0-9_]), and $ again; the heredoc then extends to the next occurrence of the same delimiter. An unterminated delimiter is not a heredoc, and its $ stays an ordinary character. The region is copied verbatim, so quotes, comment markers and semicolons inside it cannot affect the split.
  • Backslash escapes are now recognized inside backticks as well, matching quotedString<''>()`.

No parser rewrite, no new dependency, no change to test-hint.ts or the backends.

Resulting statement counts on the files named in the issue now match the official lexer: 03011 82 -> 91, 04038 28 -> 43, 04097 15 -> 18, and 02683/02685/02686/02687/03032 split at the correct boundary. A 150-file sample of tests/queries/0_stateless produces byte-identical output before and after, so no currently allowlisted file changes behavior. Adding the affected tests to upstream-allowlist.txt is deliberately left out: per tests/clickhouse-test-runner/AGENTS.md, allowlist growth is validated separately through the harness against both CI server versions.

Test Plan

New cases in tests/clickhouse-test-runner/__tests__/split-queries.test.ts (heredoc with quotes/backslashes, tagged heredoc, statement boundaries after a heredoc, unterminated $$, $foo not being a heredoc, escaped backtick in a quoted identifier). All four heredoc/backtick cases fail on main and pass with the fix.

Commands run locally (Node 24.22.1, Windows):

cd tests/clickhouse-test-runner
npx vitest run                 # 7 files, 86 tests passed
npx tsc --noEmit               # clean (after building packages/datatype-parser and the rowbinary skill)
npm run lint                   # eslint --max-warnings=0, clean
npx prettier --check src/split-queries.ts __tests__/split-queries.test.ts   # clean

Statement counts old vs new were compared by running both implementations over the upstream files from the issue plus a 150-file sample of tests/queries/0_stateless (ClickHouse master).

No changelog entry: tests/clickhouse-test-runner is a private, unpublished workspace package with no CHANGELOG.md, and no published package changes.

Checklist

  • Unit tests covering the fixed behaviour were added
  • Changelog: not applicable (private test-harness package, no published API change)
  • Docs: not applicable (internal harness behaviour)

…ries()

The statement splitter in the upstream SQL test harness only knew single
quotes, double quotes, backticks, backslash escapes outside backticks, and
the two SQL comment styles. Two constructs in the server lexer were missing:

- Dollar quoting ($$...$$ and $tag$...$tag$). A quote inside the heredoc
  toggled the splitter's quote state, so every following statement was
  merged into one, and a `;` inside the heredoc could split it apart.
- A backslash-escaped backtick inside a quoted identifier, which closed the
  identifier early and left it open for the rest of the file.

Both are implemented the way the server lexer does it (see
src/Parsers/Lexer.cpp): the opening delimiter is `$`, an optional tag of
word characters, and `$` again, and the heredoc runs to the next occurrence
of that same delimiter; an unterminated delimiter is not a heredoc. Quoted
identifiers now honor backslash escapes like string literals.

Statement counts on the upstream files from ClickHouse#1096 now match the official
lexer: 03011_definitive_guide_to_cast 82 -> 91, 04038_ascii_cjk_tokenizer
28 -> 43, 04097_tuple_inside_nullable_subcolumn_descendants 15 -> 18, and
the 02683/02685/02686/02687/03032 heredoc files split at the right
boundary. A 150-file sample of tests/queries/0_stateless produces
unchanged output.
Copilot AI balanced review requested due to automatic review settings November 1, 2026 10:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues are reported for the internal SQL statement-splitting changes.

No open issues 🎉

What changed in this PR

Fixes #1096 by aligning the upstream SQL test harness’s statement splitter with ClickHouse’s handling of dollar-quoted strings and escaped backticks. Changes are limited to the internal harness; published client APIs are unaffected.

Changes:

  • Preserve $$...$$ and $tag$...$tag$ heredocs without interpreting their contents as statement boundaries.
  • Recognize backslash escapes inside backtick-quoted identifiers.
  • Add regression tests for heredocs, non-heredoc dollar sequences, and escaped backticks.
File Description
tests/​clickhouse-test-runner/​src/​split-queries.ts Adds heredoc detection and backtick escape handling.
tests/​clickhouse-test-runner/​__tests__/​split-queries.test.ts Adds six regression cases covering the corrected splitting behavior.

Review effort: Balanced

@ccoltx ccoltx mentioned this pull request Nov 2, 2026

This branch has not been deployed

No deployments
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.

test-runner: splitQueries() mis-splits $$ heredocs and escaped backticks (8 upstream tests affected)

2 participants