BuzzHouse gains coverage for text indexes, regular expressions, hypothetical
projections, time series, the remaining MergeTree engines, parts and
partitions, `LIMIT AFTER`/`UNTIL`, the aggregates and the `IN table` form that
were missing, and a location for Delta Lake tables. The session, table and hot
table settings lists are refreshed against master, which includes dropping
entries whose settings no longer exist.
`QueryFuzzer` is the other half of the change, extending the mutations it
applies while keeping every one of them re-parseable.
Squashed from 25 commits and 16 merges of master; the tree is unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The product name is written `ClickHouse` - one word, with a capital `C`
and a capital `H`. Two case variants are accepted, because a mixed case
is unusable there: `clickhouse` for identifiers, package, binary and host
names, and `CLICKHOUSE` for macros and environment variables. Everything
else - `Clickhouse`, `clickHouse`, `click_house`, `CLICK_HOUSE`,
`click-house`, `Click House` - is a misspelling, and the new
`clickhouse_spelling` check of the style job reports it, in code as well
as in comments, messages, documentation and file names.
The check searches every file tracked by git, and the file names
themselves. It skips:
* `contrib` - third-party sources;
* the generated locale directories of the documentation - a machine
translation of the English pages, which are checked instead;
* release notes - a record of what was published;
* `docs/_specs` - API specifications pinned from their generator;
* regions between `AUTOGENERATED_START` and `AUTOGENERATED_END` markers -
their source of truth (a `FunctionDocumentation` string, for instance)
is checked instead;
* URLs - a link whose path spells the name differently is not a mistake
we can fix, and rewriting it would only break the link;
* the exceptions listed in `clickhouse_spelling_ignore.txt` - text that
is not ours to spell: names defined by other projects (the
`ClickhouseClientOptions` of our Azure SDK fork, the `clickHouse*`
parameters of Google's Dataflow templates), verbatim quotations (Stack
Overflow post titles shown as query output), and the misspellings that
tests feed to the server on purpose (`LIKE` / `ILIKE` case variants, an
unknown URI scheme).
The rest of the change fixes the 191 misspellings this found. Most are
prose and comments; the renamed identifiers are `isClickhouseApp`,
`getClickhouseAttemptNumber` / `setClickhouseAttemptNumber`,
`getClickhouseTableSchemaById` / `hasClickhouseTableSchemaById`, the
`Clickhouse*` classes of `clickhouse-diagnostics`, the `tabClickhouse` /
`btnQueryClickhouse` element ids of the `utils` web tools, and
`clickHousePartsInserter.js`. Three of them are visible to tests: the
`X-Clickhouse-Format` HTTP header, the `SOURCE(Clickhouse(...))`
dictionary source and a directory named `Clickhouse`; the first two are
matched case-insensitively by the server (Poco header collections are
case-insensitive, and the parser lowercases the source name), which I
confirmed against a running server.
The rule is also written down in the style guide.
Conflicts:
- `.github/workflows/pull_request.yml`: took master's regenerated `needs`
list (which gained `build_profile_diff`) and re-added this PR's
`ast_fuzzer_amd_release_oracle` job.
- `src/Interpreters/executeQuery.cpp`: master wrapped the fuzzed query
execution in a `ThreadGroupSwitcher`; this PR moved that execution into
an inner scope so the `BlockIO` callbacks are destroyed before the
oracle runs. Kept both: the switcher is now declared outside the inner
scope so it also covers the oracle's nested queries, which run on the
same `fuzz_context`.
Also moved the `ast_fuzzer_oracle` entry in `SettingsChangesHistory` from
the released 26.7 block to the current 26.8 block.
The dialect was contributed in 2022 and abandoned by its authors; the
rewrite they promised in #62668 was closed unmerged. Since then it has
been emergency-disabled once (#59305) and gated behind
`allow_experimental_kusto_dialect` (#74224), and issue #61742 ("Remove
KQL support if this code will not be fixed") has stayed open.
The implementation translated a KQL token stream directly into
ClickHouse SQL *text* and re-parsed it. Everything below follows from
that:
- KQL string literals were spliced into generated SQL unescaped, so
`T | where s contains "x') OR 1 = 1 OR ilike(s, 'y"` injected
arbitrary expressions -- and `contains '50%'` matched `'50x'`
because LIKE metacharacters passed through.
- No types were available while translating, so 14 sites emitted
runtime `toTypeName()` dispatch and datetimes were modelled as
strings truncated to 27 characters.
- Arguments were SQL text, so a dozen sites called `std::stoi` on it;
`format_timespan(col, 'hh:mm')` failed with "stoi: no conversion".
- 28 of the 237 registered functions were stubs that returned the raw
KQL name into the generated SQL, including every `series_*`.
- `let` bindings lived in a `static thread_local` map that, by its own
comment, leaked between unrelated queries.
This commit removes the implementation and every trace of it: the
parser, the `kusto` dialect and its experimental setting, the `kusto`
value of `interval_output_format` and the interval serialization it
drove, the client/server call sites, the fuzzer and style-check
carve-outs, and the tests. A correct implementation is added next.
Two notes on what was deliberately kept. `ASTSelectQuery::normalize
ChildrenOrder` stays -- several other parsers use it -- with its comment
generalized. `04305_parser_error_message_oob_101143.sh` stays as a
regression test for the error-formatter buffer overflow; its rationale
is rewritten, since the parser it originally exercised is now gone.
Release history in CHANGELOG.md, docs/changelogs/ and
SettingsChangesHistory.cpp is left untouched.
With `ast_fuzzer_runs > 0` the server mutates the client's seed query again,
and the `AST_FUZZER_ORACLE_MISMATCH` exception reaching the client did not
carry that final fuzzed query — the CI artifact (`fuzzer.log`) omitted the
real reproducer. Rethrow the mismatch with the server-side fuzzed query
appended, and label the client-side seed clearly in `FuzzLoop`.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The client-side AST fuzzer loop swallowed every exception thrown during a
fuzzing step: the `catch (...)` handler recorded the error, the loop bottom
reset it, and fuzzing continued. When the failure mode is persistent - most
importantly a dead server, where the reconnection attempt inside
`processParsedSingleQuery` throws instantly - the client sprints through the
remaining corpus at hundreds of steps per second without contacting the
server and exits with code 0, which the job reports as "Fuzzer exited with
success".
Evidence from `AST fuzzer (amd_debug, targeted)` on PR #109061
(https://s3.amazonaws.com/clickhouse-test-reports/json.html?PR=109061&sha=1419f6b7e95c81c812f945c06333998b92d56ad3&name_0=PR&name_1=AST+fuzzer+%28amd_debug%2C+targeted%29):
`fuzzer.log` records 68972 fuzzing steps, of which 52837 produced no outcome
(silent exception), while `server.log` shows the server received only 209
queries within a 47-second window before dying. On PR #106250
(https://s3.amazonaws.com/clickhouse-test-reports/json.html?PR=106250&sha=latest&name_0=PR&name_1=AST+fuzzer+%28amd_debug%2C+targeted%29)
a 5-file corpus with ~20 SELECT statements (about 20000 fuzzing steps, over
an hour of work at the measured debug-build rate of 2-6 steps/s) "completed"
in 74 seconds and the job passed. Overall, 13-33% of targeted AST fuzzer
runs per month finish in under 8 minutes of their 30-minute budget.
Client fixes (`programs/client/FuzzLoop.cpp`):
- Print thrown exceptions in the fuzzing-step catch handlers instead of
swallowing them silently, so `fuzzer.log` shows what actually happened.
- After a thrown exception, check the connection via `tryToReconnect` (the
same check `processASTFuzzerStep` does for errors received without
throwing) and stop fuzzing when the server is gone instead of uselessly
sprinting through the rest of the corpus.
- Register query parameters generated by `QueryFuzzer` (from
`getLastQueryParameters`) for client-side substitution, mirroring the
server-side fuzzer in `executeASTFuzzerQueries`; previously any fuzzed
query containing a substituted `{name:type}` parameter failed with
"Substitution ... is not set" before reaching the server.
Job fix (`ci/jobs/scripts/fuzzer/run-fuzzer.sh`):
- When the AST fuzzer walks the whole corpus and exits 0 with a meaningful
part of the FUZZ_TIME_LIMIT budget remaining, restart it (each pass uses a
fresh random seed) instead of ending the job after a couple of minutes.
This matters for the targeted variant, whose corpus is a handful of test
files. The restart is gated on a server liveness probe so a dead server
still terminates the job for classification.
Add a correctness-oracle mode to the AST fuzzer (`ast_fuzzer_oracle`) that runs
metamorphic checks on each successfully-executed fuzzed query and raises
`AST_FUZZER_ORACLE_MISMATCH` when a rewrite that must preserve results does not:
- TLP (Three-Valued Logic Partitioning) for WHERE / HAVING / DISTINCT: a query
and its `p` / `NOT p` / `p IS NULL` partition-union must return the same rows.
- NoREC-style aggregate/count equivalences.
- Rewrites over GROUP BY (incl. ROLLUP/CUBE/GROUPING SETS/WITH TOTALS), JOINs,
and aggregate-state combinators.
`QueryOracleChecker` performs the checks with fail-closed guards
(`isSafeForOracle`) so non-deterministic, session-stateful, or otherwise unsafe
shapes are skipped rather than reported. `QueryFuzzer` gains oracle-shaped
mutation generation; `executeQuery` runs the oracle after the fuzzed query in an
inner scope so result callbacks are released first. Includes the client
`FuzzLoop`, the setting + error code, CI wiring (`ast_fuzzer_job`, workflow
needs-lists, run-fuzzer tweaks), and regression tests.
Squashed and rebased on latest master.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>