Skip to content

Commit ea9c325

Browse files
alambcomphead
andauthored
Minor: Extract parent/child limit calculation into a function, improve docs (#10501)
* Minor: Extract parent/child limit calculation into a function, improve docs * Update datafusion/optimizer/src/push_down_limit.rs Co-authored-by: Oleks V <[email protected]> --------- Co-authored-by: Oleks V <[email protected]>
1 parent bed57df commit ea9c325

File tree

1 file changed

+77
-39
lines changed

1 file changed

+77
-39
lines changed

datafusion/optimizer/src/push_down_limit.rs

Lines changed: 77 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
//! [`PushDownLimit`] pushes `LIMIT` earlier in the query plan
1919
20+
use std::cmp::min;
2021
use std::sync::Arc;
2122

2223
use crate::optimizer::ApplyOrder;
@@ -56,47 +57,12 @@ impl OptimizerRule for PushDownLimit {
5657

5758
if let LogicalPlan::Limit(child) = &*limit.input {
5859
// Merge the Parent Limit and the Child Limit.
59-
60-
// Case 0: Parent and Child are disjoint. (child_fetch <= skip)
61-
// Before merging:
62-
// |........skip........|---fetch-->| Parent Limit
63-
// |...child_skip...|---child_fetch-->| Child Limit
64-
// After merging:
65-
// |.........(child_skip + skip).........|
66-
// Before merging:
67-
// |...skip...|------------fetch------------>| Parent Limit
68-
// |...child_skip...|-------------child_fetch------------>| Child Limit
69-
// After merging:
70-
// |....(child_skip + skip)....|---(child_fetch - skip)-->|
71-
72-
// Case 1: Parent is beyond the range of Child. (skip < child_fetch <= skip + fetch)
73-
// Before merging:
74-
// |...skip...|------------fetch------------>| Parent Limit
75-
// |...child_skip...|-------------child_fetch------------>| Child Limit
76-
// After merging:
77-
// |....(child_skip + skip)....|---(child_fetch - skip)-->|
78-
79-
// Case 2: Parent is in the range of Child. (skip + fetch < child_fetch)
80-
// Before merging:
81-
// |...skip...|---fetch-->| Parent Limit
82-
// |...child_skip...|-------------child_fetch------------>| Child Limit
83-
// After merging:
84-
// |....(child_skip + skip)....|---fetch-->|
85-
let parent_skip = limit.skip;
86-
let new_fetch = match (limit.fetch, child.fetch) {
87-
(Some(fetch), Some(child_fetch)) => {
88-
Some(min(fetch, child_fetch.saturating_sub(parent_skip)))
89-
}
90-
(Some(fetch), None) => Some(fetch),
91-
(None, Some(child_fetch)) => {
92-
Some(child_fetch.saturating_sub(parent_skip))
93-
}
94-
(None, None) => None,
95-
};
60+
let (skip, fetch) =
61+
combine_limit(limit.skip, limit.fetch, child.skip, child.fetch);
9662

9763
let plan = LogicalPlan::Limit(Limit {
98-
skip: child.skip + parent_skip,
99-
fetch: new_fetch,
64+
skip,
65+
fetch,
10066
input: Arc::new((*child.input).clone()),
10167
});
10268
return self
@@ -217,6 +183,78 @@ impl OptimizerRule for PushDownLimit {
217183
}
218184
}
219185

186+
/// Combines two limits into a single
187+
///
188+
/// Returns the combined limit `(skip, fetch)`
189+
///
190+
/// # Case 0: Parent and Child are disjoint. (`child_fetch <= skip`)
191+
///
192+
/// ```text
193+
/// Before merging:
194+
/// |........skip........|---fetch-->| Parent Limit
195+
/// |...child_skip...|---child_fetch-->| Child Limit
196+
/// ```
197+
///
198+
/// After merging:
199+
/// ```text
200+
/// |.........(child_skip + skip).........|
201+
/// ```
202+
///
203+
/// Before merging:
204+
/// ```text
205+
/// |...skip...|------------fetch------------>| Parent Limit
206+
/// |...child_skip...|-------------child_fetch------------>| Child Limit
207+
/// ```
208+
///
209+
/// After merging:
210+
/// ```text
211+
/// |....(child_skip + skip)....|---(child_fetch - skip)-->|
212+
/// ```
213+
///
214+
/// # Case 1: Parent is beyond the range of Child. (`skip < child_fetch <= skip + fetch`)
215+
///
216+
/// Before merging:
217+
/// ```text
218+
/// |...skip...|------------fetch------------>| Parent Limit
219+
/// |...child_skip...|-------------child_fetch------------>| Child Limit
220+
/// ```
221+
///
222+
/// After merging:
223+
/// ```text
224+
/// |....(child_skip + skip)....|---(child_fetch - skip)-->|
225+
/// ```
226+
///
227+
/// # Case 2: Parent is in the range of Child. (`skip + fetch < child_fetch`)
228+
/// Before merging:
229+
/// ```text
230+
/// |...skip...|---fetch-->| Parent Limit
231+
/// |...child_skip...|-------------child_fetch------------>| Child Limit
232+
/// ```
233+
///
234+
/// After merging:
235+
/// ```text
236+
/// |....(child_skip + skip)....|---fetch-->|
237+
/// ```
238+
fn combine_limit(
239+
parent_skip: usize,
240+
parent_fetch: Option<usize>,
241+
child_skip: usize,
242+
child_fetch: Option<usize>,
243+
) -> (usize, Option<usize>) {
244+
let combined_skip = child_skip.saturating_add(parent_skip);
245+
246+
let combined_fetch = match (parent_fetch, child_fetch) {
247+
(Some(parent_fetch), Some(child_fetch)) => {
248+
Some(min(parent_fetch, child_fetch.saturating_sub(parent_skip)))
249+
}
250+
(Some(parent_fetch), None) => Some(parent_fetch),
251+
(None, Some(child_fetch)) => Some(child_fetch.saturating_sub(parent_skip)),
252+
(None, None) => None,
253+
};
254+
255+
(combined_skip, combined_fetch)
256+
}
257+
220258
fn push_down_join(join: &Join, limit: usize) -> Option<Join> {
221259
use JoinType::*;
222260

0 commit comments

Comments
 (0)