Repository navigation
fix: validate sort pushdown through custom execution plans - #26118
geoffreyclaude wants to merge 2 commits into
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #26118 +/- ##
==========================================
+ Coverage 82.73% 82.74% +0.01%
==========================================
Files 1147 1148 +1
Lines 449213 449974 +761
Branches 449213 449974 +761
==========================================
+ Hits 371634 372320 +686
- Misses 54929 54968 +39
- Partials 22650 22686 +36 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
b01b268 to
0716299
Compare
5d0adb0 to
3d94eb9
Compare
86c2b24 to
9aa9bee
Compare
9aa9bee to
40c665e
Compare
jayzhan211
left a comment
There was a problem hiding this comment.
The fix for the -a AS a case looks right to me. Two comments inline: one on keeping pushdown for transparent custom nodes, and one on documenting the behavior change.
| Ok(Some(child_requirements)) | ||
| } else { | ||
| handle_custom_pushdown(plan, parent_required, &maintains_input_order) | ||
| // Preserving row positions does not identify the input expressions needed |
There was a problem hiding this comment.
This also stops pushdown through custom nodes that really are transparent, and try_pushdown_sort can't bring it back when the node sits above a join, union or window, since only sources and pass-through operators implement it. You can see it in the updated test_custom_node_keeps_sort_with_compatible_input_ordering snapshot, which now has two sorts instead of one. Your issue's expected behavior (push only when the node's own properties prove the ordering) seems to cover both cases. I tried keeping handle_custom_pushdown and adding this check before returning Some(result):
let probe_children = plan_children
.iter()
.zip(&result)
.map(|(child, req)| match req {
Some(req) => Arc::new(
SortExec::new(LexOrdering::from(req.first().clone()), Arc::clone(child))
.with_preserve_partitioning(true),
) as Arc<dyn ExecutionPlan>,
None => Arc::clone(child),
})
.collect();
let probe = Arc::clone(plan).replace_children(
probe_children,
ReplaceChildrenOptions::new(ChildrenPropertiesMode::Recompute),
)?;
if !probe
.equivalence_properties()
.ordering_satisfy_requirement(requirement)?
{
return Ok(None);
}With this, your -a AS a slt still keeps the sort, the snapshot above goes back to a single sort, and no other optimizer test or slt changes (Filter/Repartition still need their explicit exclusion). Would you consider this instead? If you'd rather keep the conservative default here, a follow-up is fine too.
| /// | ||
| /// This describes row sequence, not how input expressions map to outputs. | ||
| /// Custom nodes that support sort pushdown should implement | ||
| /// [`Self::try_pushdown_sort`]; returning `true` here alone does not opt in. |
There was a problem hiding this comment.
This changes optimizer behavior for downstream ExecutionPlan implementations: nodes that return true from maintains_input_order() will now keep sorts above them. Could you add a short note to docs/source/library-user-guide/upgrading/56.0.0.md saying how to restore pushdown, and add the api change label? If you go with the validated fallback from the other comment, this note isn't needed.
@jayzhan211 Thanks for the in-depth review! I'm going back to design as I'm not happy with the current approach. I'll take your suggestions into account and put this back in draft in the meantime. |
40c665e to
5fcc93d
Compare
Keep sorts above operators without explicit sort-pushdown handling. Preserve known built-in input mappings and make custom-node support opt-in through the existing try_pushdown_sort API. Cover correct query results and sort placement for a value-transforming custom projection, built-in input mappings, and explicit custom support. Closes apache#26656.
5fcc93d to
2672c49
Compare
Which issue does this PR close?
Closes #26656.
Rationale for this change
Sort pushdown moves a sort before another operator. The generic fallback could assume that an output sort key referred to the same input column, even when a custom node reordered or transformed its columns. This could return incorrectly ordered results or fail plan validation.
maintains_input_order()describes row sequence, even when column values change. For a custom node computing-a AS a, moving an ascending sort below it reverses the requested value ordering:Native
ProjectionExecalready has specialized handling that maps forwarded columns and rejects pushdown through computed projections. The generic fallback needs to validate its proposed ordering against the custom node's own properties.What changes are included in this PR?
Keep the existing generic fallback for column sort keys and validate its proposed child orderings before accepting them:
Transparent custom nodes retain sort pushdown and compatible-sort consolidation without implementing another hook. A few safeguards keep this validation from changing execution:
1 / xearlier, for example, could fail on a zero-valued row the node would otherwise discard.fetch(a row limit) keep their selected rows; sorting their input could select different rows.The existing filter and repartition exclusions remain.
There are no new APIs or mandatory custom-node opt-ins.
What is the testing strategy for this PR?
Executable SQL regressions cover a negated column, a renamed/reordered projection, a computed key on filtered rows, and a fetched custom node, checking both returned rows and the retained sort. Focused optimizer tests verify that compatible sorts still consolidate, conflicting mandatory input orderings remain satisfied even with a shared prefix, and fetched custom scans retain the outer sort when needed.
Local validation uses the focused optimizer unit and integration tests,
sort_pushdown.slt, formatting, the CI Clippy script, and documentation checks. No full extended test suite was run.Are there any user-facing changes?
Affected custom nodes produce correctly ordered results. Existing safe pushdown continues through transparent custom nodes using their recomputed ordering properties.
Developed with AI assistance. The validated fallback follows Jayzhan211's review suggestion.