Skip to main content

dbx_core/sql/optimizer/
limit_pushdown.rs

1//! Rule 4: Limit Pushdown
2//!
3//! LIMIT를 하위 노드에 적용하여 조기 종료
4
5use crate::error::DbxResult;
6use crate::sql::planner::LogicalPlan;
7
8use super::OptimizationRule;
9
10/// LIMIT를 하위 노드에 적용하여 조기 종료
11pub struct LimitPushdownRule;
12
13impl OptimizationRule for LimitPushdownRule {
14    fn name(&self) -> &str {
15        "LimitPushdown"
16    }
17
18    fn apply(&self, plan: LogicalPlan) -> DbxResult<LogicalPlan> {
19        self.push_down(plan)
20    }
21}
22
23impl LimitPushdownRule {
24    fn push_down(&self, plan: LogicalPlan) -> DbxResult<LogicalPlan> {
25        match plan {
26            LogicalPlan::Limit {
27                input,
28                count,
29                offset,
30            } => {
31                let optimized_input = self.push_down(*input)?;
32                match optimized_input {
33                    LogicalPlan::Project {
34                        input: project_input,
35                        projections: columns,
36                    } if offset == 0 => {
37                        let pushed = LogicalPlan::Limit {
38                            input: project_input,
39                            count,
40                            offset: 0,
41                        };
42                        Ok(LogicalPlan::Project {
43                            input: Box::new(pushed),
44                            projections: columns,
45                        })
46                    }
47                    LogicalPlan::Limit {
48                        input: inner_input,
49                        count: inner_count,
50                        offset: inner_offset,
51                    } => {
52                        let final_count = count.min(inner_count);
53                        let final_offset = offset + inner_offset;
54                        Ok(LogicalPlan::Limit {
55                            input: inner_input,
56                            count: final_count,
57                            offset: final_offset,
58                        })
59                    }
60                    other => Ok(LogicalPlan::Limit {
61                        input: Box::new(other),
62                        count,
63                        offset,
64                    }),
65                }
66            }
67            LogicalPlan::Project {
68                input,
69                projections: columns,
70            } => Ok(LogicalPlan::Project {
71                input: Box::new(self.push_down(*input)?),
72                projections: columns,
73            }),
74            LogicalPlan::Filter { input, predicate } => Ok(LogicalPlan::Filter {
75                input: Box::new(self.push_down(*input)?),
76                predicate,
77            }),
78            LogicalPlan::Sort { input, order_by } => Ok(LogicalPlan::Sort {
79                input: Box::new(self.push_down(*input)?),
80                order_by,
81            }),
82            LogicalPlan::Aggregate {
83                input,
84                group_by,
85                aggregates,
86            } => Ok(LogicalPlan::Aggregate {
87                input: Box::new(self.push_down(*input)?),
88                group_by,
89                aggregates,
90            }),
91            other => Ok(other),
92        }
93    }
94}