Skip to content

Commit 163314d

Browse files
authored
fix: fetch is missed in the EnsureSorting (#14192)
* fix: fetch is missed in the EnsureSorting * fix conflict * resolve comments from alamb * update
1 parent d3f1c9a commit 163314d

File tree

4 files changed

+32
-13
lines changed

4 files changed

+32
-13
lines changed

datafusion/core/src/physical_optimizer/enforce_sorting.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,11 @@ impl PhysicalOptimizerRule for EnforceSorting {
186186
)
187187
})
188188
.data()?;
189-
190189
// Execute a top-down traversal to exploit sort push-down opportunities
191190
// missed by the bottom-up traversal:
192191
let mut sort_pushdown = SortPushDown::new_default(updated_plan.plan);
193192
assign_initial_requirements(&mut sort_pushdown);
194193
let adjusted = pushdown_sorts(sort_pushdown)?;
195-
196194
adjusted
197195
.plan
198196
.transform_up(|plan| Ok(Transformed::yes(replace_with_partial_sort(plan)?)))
@@ -403,7 +401,10 @@ fn analyze_immediate_sort_removal(
403401
{
404402
// Replace the sort with a sort-preserving merge:
405403
let expr = LexOrdering::new(sort_exec.expr().to_vec());
406-
Arc::new(SortPreservingMergeExec::new(expr, Arc::clone(sort_input))) as _
404+
Arc::new(
405+
SortPreservingMergeExec::new(expr, Arc::clone(sort_input))
406+
.with_fetch(sort_exec.fetch()),
407+
) as _
407408
} else {
408409
// Remove the sort:
409410
node.children = node.children.swap_remove(0).children;
@@ -626,11 +627,12 @@ fn remove_corresponding_sort_from_sub_plan(
626627
// If there is existing ordering, to preserve ordering use
627628
// `SortPreservingMergeExec` instead of a `CoalescePartitionsExec`.
628629
let plan = Arc::clone(&node.plan);
630+
let fetch = plan.fetch();
629631
let plan = if let Some(ordering) = plan.output_ordering() {
630-
Arc::new(SortPreservingMergeExec::new(
631-
LexOrdering::new(ordering.to_vec()),
632-
plan,
633-
)) as _
632+
Arc::new(
633+
SortPreservingMergeExec::new(LexOrdering::new(ordering.to_vec()), plan)
634+
.with_fetch(fetch),
635+
) as _
634636
} else {
635637
Arc::new(CoalescePartitionsExec::new(plan)) as _
636638
};

datafusion/core/src/physical_optimizer/replace_with_order_preserving_variants.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,20 @@ fn plan_with_order_preserving_variants(
100100
// Flag indicating that it is desirable to replace `CoalescePartitionsExec`s
101101
// with `SortPreservingMergeExec`s:
102102
is_spm_better: bool,
103+
fetch: Option<usize>,
103104
) -> Result<OrderPreservationContext> {
104105
sort_input.children = sort_input
105106
.children
106107
.into_iter()
107108
.map(|node| {
108109
// Update descendants in the given tree if there is a connection:
109110
if node.data {
110-
plan_with_order_preserving_variants(node, is_spr_better, is_spm_better)
111+
plan_with_order_preserving_variants(
112+
node,
113+
is_spr_better,
114+
is_spm_better,
115+
fetch,
116+
)
111117
} else {
112118
Ok(node)
113119
}
@@ -133,7 +139,8 @@ fn plan_with_order_preserving_variants(
133139
if let Some(ordering) = child.output_ordering() {
134140
// When the input of a `CoalescePartitionsExec` has an ordering,
135141
// replace it with a `SortPreservingMergeExec` if appropriate:
136-
let spm = SortPreservingMergeExec::new(ordering.clone(), Arc::clone(child));
142+
let spm = SortPreservingMergeExec::new(ordering.clone(), Arc::clone(child))
143+
.with_fetch(fetch);
137144
sort_input.plan = Arc::new(spm) as _;
138145
sort_input.children[0].data = true;
139146
return Ok(sort_input);
@@ -252,6 +259,7 @@ pub(crate) fn replace_with_order_preserving_variants(
252259
requirements.children.swap_remove(0),
253260
is_spr_better || use_order_preserving_variant,
254261
is_spm_better || use_order_preserving_variant,
262+
requirements.plan.fetch(),
255263
)?;
256264

257265
// If the alternate plan makes this sort unnecessary, accept the alternate:

datafusion/core/src/physical_optimizer/sort_pushdown.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ pub fn assign_initial_requirements(node: &mut SortPushDown) {
6363
for (child, requirement) in node.children.iter_mut().zip(reqs) {
6464
child.data = ParentRequirements {
6565
ordering_requirement: requirement,
66-
fetch: None,
66+
// If the parent has a fetch value, assign it to the children
67+
// Or use the fetch value of the child.
68+
fetch: child.plan.fetch(),
6769
};
6870
}
6971
}
@@ -95,6 +97,7 @@ fn pushdown_sorts_helper(
9597
.ordering_satisfy_requirement(&parent_reqs);
9698

9799
if is_sort(plan) {
100+
let sort_fetch = plan.fetch();
98101
let required_ordering = plan
99102
.output_ordering()
100103
.cloned()
@@ -103,7 +106,8 @@ fn pushdown_sorts_helper(
103106
if !satisfy_parent {
104107
// Make sure this `SortExec` satisfies parent requirements:
105108
let sort_reqs = requirements.data.ordering_requirement.unwrap_or_default();
106-
let fetch = requirements.data.fetch;
109+
// It's possible current plan (`SortExec`) has a fetch value.
110+
let fetch = requirements.data.fetch.or(sort_fetch);
107111
requirements = requirements.children.swap_remove(0);
108112
requirements = add_sort_above(requirements, sort_reqs, fetch);
109113
};
@@ -113,7 +117,7 @@ fn pushdown_sorts_helper(
113117
if let Some(adjusted) =
114118
pushdown_requirement_to_children(&child.plan, &required_ordering)?
115119
{
116-
let fetch = child.plan.fetch();
120+
let fetch = sort_fetch.or_else(|| child.plan.fetch());
117121
for (grand_child, order) in child.children.iter_mut().zip(adjusted) {
118122
grand_child.data = ParentRequirements {
119123
ordering_requirement: order,

datafusion/sqllogictest/test_files/topk.slt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ select * from topk order by x desc limit 3;
4949
8
5050
5
5151

52-
52+
query I
53+
select * from (select * from topk limit 8) order by x limit 3;
54+
----
55+
0
56+
1
57+
2
5358

5459

5560
statement ok

0 commit comments

Comments
 (0)