Skip to content

fix: preserve nullability for non-empty scalar subqueries - #24534

Open
fornwall wants to merge 2 commits into
apache:mainfrom
fornwall:min-rows
Open

fix: preserve nullability for non-empty scalar subqueries#24534
fornwall wants to merge 2 commits into
apache:mainfrom
fornwall:min-rows

Conversation

@fornwall

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Rationale for this change

#24516 conservatively made every scalar subquery nullable because an empty result evaluates to NULL. Plans guaranteed to return at least one row, such as ungrouped aggregates, cannot produce that empty-result NULL; marking them nullable loses schema precision and prevents valid expression simplification.

What changes are included in this PR?

  • Adds a conservative LogicalPlan::min_rows() lower bound.
  • Uses the lower bound in logical schema derivation. Physical scalar-subquery planning now defers to Expr::nullable instead of hardcoding nullable = true, so the logical rule is the single source of truth.
  • Makes max_rows() account for the one-row form of EmptyRelation, keeping both bounds consistent.

Are these changes tested?

Yes. Unit tests cover row bounds, logical schema derivation, optimizer simplification, and physical expression nullability for both possibly empty and guaranteed non-empty scalar subqueries. A sqllogictest pins the user-visible effect: EXPLAIN shows that (SELECT count(*) FROM empty_table) IS NULL now folds to false, eliminating the subquery from the plan. (Query results alone cannot show the change: a guaranteed non-empty scalar subquery never evaluates to NULL at runtime.)

As an ablation check, restoring the conservative always-nullable behavior makes the logical, optimizer, physical, and sqllogictest tests fail.

The required all-feature Clippy check and extended workspace test suite pass.

Are there any user-facing changes?

Yes. Scalar subqueries proven to return at least one row now preserve the nullability of their projected field, allowing valid simplification. Potentially empty scalar subqueries remain nullable. LogicalPlan::min_rows() is a new public API.


AI usage: Implemented with Codex; reviewed and test coverage extended with Claude Code. I reviewed the code and made modifications where appropriate.

Signed-off-by: Fredrik Fornwall <fredrik@fornwall.net>
@github-actions github-actions Bot added logical-expr Logical plan and expressions physical-expr Changes to the physical-expr crates optimizer Optimizer rules sqllogictest SQL Logic Tests (.slt) labels Aug 20, 2026
@codecov-commenter

codecov-commenter commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.47059% with 44 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.31%. Comparing base (dbdc627) to head (f4836f7).
⚠️ Report is 10 commits behind head on main.

Files with missing lines Patch % Lines
datafusion/expr/src/logical_plan/plan.rs 70.22% 5 Missing and 34 partials ⚠️
datafusion/physical-expr/src/planner.rs 76.19% 2 Missing and 3 partials ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##             main   #24534    +/-   ##
========================================
  Coverage   81.31%   81.31%            
========================================
  Files        1117     1117            
  Lines      395911   396437   +526     
  Branches   395911   396437   +526     
========================================
+ Hits       321918   322373   +455     
- Misses      55177    55200    +23     
- Partials    18816    18864    +48     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

logical-expr Logical plan and expressions optimizer Optimizer rules physical-expr Changes to the physical-expr crates sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scalar subquery returning no rows is incorrectly marked non-nullable

2 participants