Skip to content

fix(query): match nullable scalar correlation keys - #20408

Draft
youngsofun wants to merge 1 commit into
databendlabs:mainfrom
youngsofun:codex/fix-scalar-null-correlation
Draft

fix(query): match nullable scalar correlation keys#20408
youngsofun wants to merge 1 commit into
databendlabs:mainfrom
youngsofun:codex/fix-scalar-null-correlation

Conversation

@youngsofun

@youngsofun youngsofun commented Aug 28, 2026

Copy link
Copy Markdown
Member

I hereby agree to the terms of the CLA available at: https://docs.databend.com/dev/policies/cla/

Summary

  • Preserve nullable correlation-group identity when reconnecting flattened scalar subquery results to outer rows
  • Keep NULL-safe join-key metadata when DPhyp rebuilds reordered joins
  • Share nullable correlation-key detection across the decorrelation paths
  • Add regression coverage for aggregate scalar subqueries with one and multiple nullable outer-only correlation keys

Motivation

Scalar subquery decorrelation computes a flattened result per correlation group and joins that result back to the outer input. For a nullable correlation key, the planner previously created this internal join with is_null_equal = false. As a result, a result computed for the NULL correlation group could not match the corresponding outer rows, so values such as MAX(v) = 7 were replaced with NULL and COUNT(*) = 1 was rewritten to zero.

This internal equality represents correlation-group identity rather than a user-written SQL = predicate. The change marks nullable keys on this reconnecting join as NULL-safe, matching the behavior already used by the correlated EXISTS and ANY decorrelation paths. User-written equality predicates retain their normal NULL semantics.

DPhyp previously reduced each join condition to a (left, right) pair and recreated every reordered condition with is_null_equal = false. That made the correctness fix dependent on whether join reordering ran. DPhyp now carries the complete JoinEquiCondition, including its NULL-safe marker, through edge reversal and join reconstruction.

This is an independent planner follow-up discovered while investigating #20364. PR #20354 already fixes #20364's executor validity issue; this PR does not change that executor fix.

Performance considerations

Databend columns are nullable by default, so more decorrelated scalar joins now correctly use NULL-safe correlation keys. Runtime bloom, in-list, and min/max filters are currently disabled for an individual NULL-safe key, and optimizer rules must not infer ordinary-equality predicates from it. This can change plan shape and reduce runtime-filter opportunities for affected queries, as visible in the updated EXPLAIN and TPC-DS Q01 expectations.

The decorrelator currently has declared expression types but no reliable relational property proving that a nullable key is non-NULL after upstream predicates. Narrowing the marker from metadata or statistics would therefore risk restoring the wrong result. This PR prioritizes correctness and explicitly retains the conservative behavior. No performance benchmark was run; deriving and propagating proven non-nullability can be evaluated as a separate optimizer improvement.

Tests

  • Unit Test
  • Logic Test
  • Benchmark Test
  • No Test - Explain why

Validation performed:

  • cargo fmt --all -- --check
  • cargo check -p databend-common-sql --lib
  • cargo clippy -p databend-common-sql --lib -- -D warnings
  • cargo build --bin databend-query --bin databend-sqllogictests
  • TEST_SUBDIR=tpcds cargo test --package databend-query --test it -- sql::planner::optimizer::optimizer_test::test_optimizer --exact --nocapture
  • databend-sqllogictests --handlers mysql,http --run tests/sqllogictests/suites/query/subquery.test --enable_sandbox --parallel 1 (277 MySQL and 277 HTTP tests passed)
  • Regression cases run with both enable_experimental_new_join = 0 and 1, including two nullable correlation keys and duplicate (NULL, 1) outer rows
  • git diff --check

Type of change

  • Bug Fix (non-breaking change which fixes an issue)
  • New Feature (non-breaking change)
  • Breaking Change (fix or feature that could cause existing functionality to not work as expected)
  • Documentation Update
  • Refactoring
  • Performance Improvement
  • Other (please describe):

AI assistance

  • AI usage: An AI coding agent investigated the scalar decorrelation and DPhyp join-reordering paths, drafted the planner fixes and regression tests, updated affected optimizer and EXPLAIN expectations, and ran the listed validation commands
  • Responsible human: @youngsofun
  • The responsible human has read every line of this diff and can explain each change

This change is Reviewable

@github-actions github-actions Bot added the pr-bugfix this PR patches a bug in codebase label Aug 28, 2026
@youngsofun
youngsofun marked this pull request as draft August 28, 2026 07:34
@youngsofun
youngsofun force-pushed the codex/fix-scalar-null-correlation branch 3 times, most recently from 6a0ce22 to 881b955 Compare August 29, 2026 10:02
@youngsofun
youngsofun force-pushed the codex/fix-scalar-null-correlation branch from 881b955 to 7e11c45 Compare August 31, 2026 02:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-bugfix this PR patches a bug in codebase

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: correlated EXISTS with cross-type join keys (INT = DECIMAL) wrongly matches NULL probe keys — and returns an unstable number of rows

1 participant