Skip to content

Fix Block structure mismatch exception in UnionStep with PREWHERE and projections#99515

Merged
alexey-milovidov merged 3 commits intomasterfrom
fix-union-block-structure-mismatch-prewhere
Mar 23, 2026
Merged

Fix Block structure mismatch exception in UnionStep with PREWHERE and projections#99515
alexey-milovidov merged 3 commits intomasterfrom
fix-union-block-structure-mismatch-prewhere

Conversation

@alexey-milovidov
Copy link
Copy Markdown
Member

Summary

  • Fix "Block structure mismatch in UnionStep" exception in debug/sanitizer builds
  • The debug assertion in UnionStep::updatePipeline fired before the existing header conversion code could fix the mismatch, causing a fatal error
  • Moved the assertion after the conversion so it only fires on truly unfixable mismatches
  • The mismatch occurs when PREWHERE optimization adds extra pass-through columns to ReadFromMergeTree output via ActionsDAG::updateHeader that are not consumed by the expression DAG above, causing plan headers and pipeline headers to diverge

Triggered by test 03722_normal_projection_key_columns.sql with parallel replicas + query_plan_remove_unused_columns = 0 (stress test settings).

Fixes #96131

CI report: https://s3.amazonaws.com/clickhouse-test-reports/json.html?REF=master&sha=73f45b0717e3a4763b7d1cde71950a076b5b00c7&name_0=MasterCI&name_1=Stress%20test%20%28azure%2C%20amd_msan%29

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):

...

Documentation entry for user-facing changes

  • Documentation is written (mandatory for new features)

🤖 Generated with Claude Code

…nd projections

Move the debug assertion in `UnionStep::updatePipeline` after the header
conversion code. Previously, the assertion fired before the existing
converting transform could fix the mismatch, causing a fatal error in
debug/sanitizer builds.

The mismatch occurs when PREWHERE optimization adds extra pass-through
columns to `ReadFromMergeTree` output via `ActionsDAG::updateHeader`
that are not consumed by the expression DAG above. This causes plan
headers and actual pipeline headers to diverge. The conversion code
already handles this gracefully by adding converting transforms, but
the assertion prevented it from running in debug builds.

Fixes #96131

https://s3.amazonaws.com/clickhouse-test-reports/json.html?REF=master&sha=73f45b0717e3a4763b7d1cde71950a076b5b00c7&name_0=MasterCI&name_1=Stress%20test%20%28azure%2C%20amd_msan%29

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@clickhouse-gh
Copy link
Copy Markdown
Contributor

clickhouse-gh bot commented Mar 15, 2026

Workflow [PR], commit [21e09b2]

Summary:


AI Review

Summary

This PR fixes a debug/ASan-only UnionStep header mismatch exception by moving assertCompatibleHeader after the existing runtime header-conversion path, and adds a focused regression test for the PREWHERE + projection + query_plan_remove_unused_columns = 0 scenario. I did not find correctness, safety, concurrency, performance, or compatibility regressions in the proposed change.

ClickHouse Rules

Item Status Notes
Deletion logging
Serialization versioning
Core-area scrutiny
No test removal
Experimental gate
No magic constants
Backward compatibility
SettingsChangesHistory.cpp
PR metadata quality
Safe rollout
Compilation time

Final Verdict

  • Status: ✅ Approve

@clickhouse-gh clickhouse-gh bot added the pr-ci label Mar 15, 2026
alexey-milovidov and others added 2 commits March 16, 2026 02:43
…WHERE and projections

This test exercises the PREWHERE + projection + `query_plan_remove_unused_columns = 0`
path that caused a debug assertion failure in `UnionStep::updatePipeline`.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@clickhouse-gh
Copy link
Copy Markdown
Contributor

clickhouse-gh bot commented Mar 21, 2026

LLVM Coverage Report

Metric Baseline Current Δ
Lines 83.90% 83.80% -0.10%
Functions 24.70% 24.60% -0.10%
Branches 76.50% 76.50% +0.00%

PR changed lines: PR changed-lines coverage: 100.00% (10/10, 0 noise lines excluded)
Diff coverage report
Uncovered code

Copy link
Copy Markdown
Member Author

@alexey-milovidov alexey-milovidov left a comment

Choose a reason for hiding this comment

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

Ok. Fairly minimal change.

@alexey-milovidov alexey-milovidov self-assigned this Mar 23, 2026
@alexey-milovidov alexey-milovidov merged commit cdf4aaa into master Mar 23, 2026
151 of 152 checks passed
@alexey-milovidov alexey-milovidov deleted the fix-union-block-structure-mismatch-prewhere branch March 23, 2026 20:29
@robot-clickhouse robot-clickhouse added the pr-synced-to-cloud The PR is synced to the cloud repo label Mar 23, 2026
alexey-milovidov added a commit that referenced this pull request Mar 30, 2026
The EXPLAIN-based plan check for consecutive Expression steps was
unreliable: it returned the same result on both the master binary
(without the plan-level fix) and the patched binary because other
plan optimizations also create consecutive Expression steps.

The actual runtime fix for the `Block structure mismatch in UnionStep`
exception was merged via PR #99515, which moved the debug assertion
in `UnionStep::updatePipeline` after the header conversion code.
This PR's plan-level fix in `optimizeUseNormalProjections` is a
defense-in-depth measure that prevents the header mismatch from
reaching the pipeline build stage.

Keep only the query correctness check as a regression test.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
alexey-milovidov added a commit that referenced this pull request Mar 30, 2026
The bugfix validation test was failing because the query-success check
alone cannot distinguish between master and this PR — PR #99515 already
handles the header mismatch at pipeline level, so the query succeeds on
both.

Add a `setStepDescription` call to the converting `ExpressionStep` in
`optimizeUseNormalProjections` so it appears as "Convert projection
output to match expected header" in EXPLAIN output. The test now checks
for this specific step description, which is absent on master and
present with this fix.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
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: Block structure mismatch in A stream: different number of columns: (STID: 0993-38e6)

2 participants