Fix logical error "Inconsistent AST formatting" on a function name containing query parameters by vitlibar · Pull Request #106635 · ClickHouse/ClickHouse · GitHub
Skip to content

Fix logical error "Inconsistent AST formatting" on a function name containing query parameters#106635

Merged
nikitamikhaylov merged 2 commits into
ClickHouse:masterfrom
vitlibar:fix-query-parameter-function-name
Jun 7, 2026
Merged

Fix logical error "Inconsistent AST formatting" on a function name containing query parameters#106635
nikitamikhaylov merged 2 commits into
ClickHouse:masterfrom
vitlibar:fix-query-parameter-function-name

Conversation

@vitlibar

@vitlibar vitlibar commented Jun 6, 2026

Copy link
Copy Markdown
Member

Changelog category (leave one):

  • CI Fix or Improvement (changelog entry is not required)

Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):

Fix logical error "Inconsistent AST formatting" on a function name containing query parameters

Closes #106358

Version info

  • Merged into: 26.6.1.474

@clickhouse-gh

clickhouse-gh Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

@clickhouse-gh clickhouse-gh Bot added the pr-ci label Jun 6, 2026
@vitlibar vitlibar force-pushed the fix-query-parameter-function-name branch from 20d1f1b to c02a6b4 Compare June 6, 2026 12:38
@clickhouse-gh

clickhouse-gh Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

LLVM Coverage Report

Metric Baseline Current Δ
Lines 84.50% 84.50% +0.00%
Functions 92.30% 92.40% +0.10%
Branches 77.10% 77.00% -0.10%

Changed lines: Changed C/C++ lines covered by tests: 11/11 (100.00%) | Lost baseline coverage: none · Uncovered code

Full report · Diff report

@nikitamikhaylov

Copy link
Copy Markdown
Member

@groeneai Investigate the test failure and provide a fix.

@groeneai

groeneai commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

@nikitamikhaylov investigated. The AST fuzzer hit on arm_asan_ubsan is a pre-existing chronic trunk bug, not caused by this PR.

Failure: Logical error: 'Bad cast from type DB::ColumnNothing to DB::ColumnVector<char8_t>'. (STID 1499-483b, c02a6b4, 2026-06-06).

Failing query (full stack in the CI report):

SELECT DISTINCT toNullable('2')
GROUP BY toString(
    isZeroOrNull(toUInt64OrDefault(9223372036854775807)),
    multiIf(
        arrayReverseSort(isZeroOrNull, [])[toNullable(65535)],
        arrayReverseSort(['00:00:00.000000000'], isZeroOrNull(-9223372036854775808), (SELECT toString(NULL))),
        '2020-02-29'
    ),
    NULL
) LIMIT -2147483647

The query uses no query parameters and no function-name parsing tricks. The crash site is src/Functions/if.cpp:1021 in FunctionIf::executeForConstAndNullableCondition:

cond_is_true = !cond_is_null && checkAndGetColumn<ColumnUInt8>(*data_column).getBool(0);

The condition column is ColumnConst(ColumnNothing). ColumnConst::onlyNull returns data->isNullAt(0), but ColumnNothing does not override isNullAt so it returns false, leaving cond_is_null = false. The code then checkAndGetColumn<ColumnUInt8> on the inner ColumnNothing and typeid_cast throws. An empty-array element access (arrayReverseSort(..., [])[...]) is the typical way the planner produces a Const(Nothing) condition reaching if/multiIf.

Cross-PR + master history (CIDB, 180d): the same crash signature (ColumnNothing to ColumnVector inside FunctionIf::executeImpl reached via executeForConstAndNullableCondition) appears on two unrelated PRs, both AST-fuzzer one-offs:

PR check branch when STID
#106635 (this one) AST fuzzer (arm_asan_ubsan) fix-query-parameter-function-name 2026-06-06 1499-483b
#104591 (optimize_row_order_if_no_order_by_v2) AST fuzzer (amd_debug, targeted) optimize_row_order_if_no_order_by_v2 2026-05-13 1499-35af

PR #104591 is purely a setting-handling change; it has zero code path overlap with if.cpp. Same exact failure shape there: multiIf(... arrayMin([]) ...) producing a Const(Nothing) condition. Both fuzzer queries follow the same pattern.

This PR's diff is parser-only (ParserFunctionNameWithLambdaArgs in src/Parsers/ExpressionListParsers.cpp plus a regression test). It cannot affect runtime evaluation of multiIf/if. The crash query parses fine without the parser change, and the symbol the failure exercises (FunctionIf::executeForConstAndNullableCondition) is unrelated to function-name parsing.

Recommendation: treat this AST fuzzer hit as a flaky/chronic finding on this PR's CI, unblock the merge, and track the underlying if.cpp bug separately. The fix is to recognize ColumnNothing (or data_column->isDummy) inside the ColumnConst unwrap branch and treat it as cond_is_null, similar to how the explicit nullable path is handled.

I will open a separate fix PR for the if.cpp executeForConstAndNullableCondition bug and reference this one.

cc @nikitamikhaylov

session: cron:clickhouse-ci-task-worker:20260607-131300

@nikitamikhaylov

Copy link
Copy Markdown
Member

@groeneai We will wait for you fixing the problem first.

@groeneai

groeneai commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

@nikitamikhaylov nikitamikhaylov self-assigned this Jun 7, 2026
@nikitamikhaylov nikitamikhaylov added this pull request to the merge queue Jun 7, 2026
Merged via the queue into ClickHouse:master with commit cfdb589 Jun 7, 2026
164 of 166 checks passed
@robot-ch-test-poll1 robot-ch-test-poll1 added the pr-synced-to-cloud The PR is synced to the cloud repo label Jun 7, 2026
pull Bot pushed a commit to Mu-L/ClickHouse that referenced this pull request Jun 9, 2026
`FunctionIf::executeForConstAndNullableCondition` aborted with
`Bad cast from type DB::ColumnNothing to DB::ColumnVector<char8_t>`
when the condition column constant-folded to
`ColumnConst(ColumnNullable(ColumnNothing))`, e.g.

    SELECT if(arraySort(x -> x, [])[toNullable(1)], 1, 2);

Two interacting issues:

1. `ColumnConst::onlyNull` was `data->isNullAt(0)`, which for
   `ColumnNullable(ColumnNothing)` reads `null_map[0]`. Whenever that
   byte happens to be `0`, `onlyNull` returned `false` even though no
   representable value exists. `ColumnNullable::onlyNull` already
   handles this by checking `nested_column->isDummy`, so `ColumnConst`
   was inconsistent.
2. `executeForConstAndNullableCondition` then unconditionally
   overwrote `cond_is_null` with the inner `Nullable`'s `null_map[0]`,
   discarding the correct outer-column value, and proceeded to
   `checkAndGetColumn<ColumnUInt8>` on the inner `ColumnNothing`
   triggering the bad cast.

This patch:

- Makes `ColumnConst::onlyNull` delegate to `data->onlyNull` so all
  callers see `Const(Nullable(Nothing))` and `Const(ColumnNothing)` as
  only-null. This matches `ColumnNullable::onlyNull`.
- Tightens the `if.cpp` branch so the inner `null_map[0]` is OR'd into
  `cond_is_null` instead of replacing it, and gates the
  `getBool`/`checkAndGetColumn<ColumnUInt8>` reads on
  `!cond_is_null`.

Surfaced by AST fuzzer STID 1499-483b on PR ClickHouse#106635 (arm_asan_ubsan)
and earlier STID 1499-35af on PR ClickHouse#104591 (amd_debug, 2026-05-13).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-ci pr-synced-to-cloud The PR is synced to the cloud repo

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Logical error: 'Inconsistent AST formatting: the original AST: (STID: 1941-1bfa)

4 participants