fix(query): match nullable scalar correlation keys - #20408
Draft
youngsofun wants to merge 1 commit into
Draft
Conversation
youngsofun
marked this pull request as draft
August 28, 2026 07:34
youngsofun
force-pushed
the
codex/fix-scalar-null-correlation
branch
3 times, most recently
from
August 29, 2026 10:02
6a0ce22 to
881b955
Compare
youngsofun
force-pushed
the
codex/fix-scalar-null-correlation
branch
from
August 31, 2026 02:22
881b955 to
7e11c45
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I hereby agree to the terms of the CLA available at: https://docs.databend.com/dev/policies/cla/
Summary
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 asMAX(v) = 7were replaced with NULL andCOUNT(*) = 1was 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 withis_null_equal = false. That made the correctness fix dependent on whether join reordering ran. DPhyp now carries the completeJoinEquiCondition, 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
Validation performed:
cargo fmt --all -- --checkcargo check -p databend-common-sql --libcargo clippy -p databend-common-sql --lib -- -D warningscargo build --bin databend-query --bin databend-sqllogictestsTEST_SUBDIR=tpcds cargo test --package databend-query --test it -- sql::planner::optimizer::optimizer_test::test_optimizer --exact --nocapturedatabend-sqllogictests --handlers mysql,http --run tests/sqllogictests/suites/query/subquery.test --enable_sandbox --parallel 1(277 MySQL and 277 HTTP tests passed)enable_experimental_new_join = 0and1, including two nullable correlation keys and duplicate(NULL, 1)outer rowsgit diff --checkType of change
AI assistance
This change is