oxisql_parse/optimizer/
pruning.rs1use crate::LogicalPlan;
8
9use super::OptPass;
10
11pub struct ProjectionPruning {
17 pub required: Vec<String>,
20}
21
22impl OptPass for ProjectionPruning {
23 fn name(&self) -> &'static str {
24 "ProjectionPruning"
25 }
26
27 fn apply(&self, plan: LogicalPlan) -> LogicalPlan {
28 if self.required.is_empty() {
29 return plan;
30 }
31 prune_projections(plan, &self.required)
32 }
33}
34
35pub(super) fn prune_projections(plan: LogicalPlan, required: &[String]) -> LogicalPlan {
38 match plan {
39 LogicalPlan::Project { input, columns } => {
40 let pruned: Vec<String> = columns
42 .into_iter()
43 .filter(|col| {
44 required
45 .iter()
46 .any(|r| col == r || col.contains(r.as_str()))
47 })
48 .collect();
49
50 let new_required = if pruned.is_empty() {
52 required.to_vec()
53 } else {
54 pruned.clone()
55 };
56 let final_cols = if pruned.is_empty() {
57 required.to_vec()
58 } else {
59 pruned
60 };
61
62 LogicalPlan::Project {
63 input: Box::new(prune_projections(*input, &new_required)),
64 columns: final_cols,
65 }
66 }
67 LogicalPlan::Filter { input, predicate } => LogicalPlan::Filter {
68 input: Box::new(prune_projections(*input, required)),
69 predicate,
70 },
71 LogicalPlan::Aggregate {
72 input,
73 group_by,
74 aggregates,
75 } => LogicalPlan::Aggregate {
76 input: Box::new(prune_projections(*input, required)),
77 group_by,
78 aggregates,
79 },
80 LogicalPlan::Sort { input, order_by } => LogicalPlan::Sort {
81 input: Box::new(prune_projections(*input, required)),
82 order_by,
83 },
84 LogicalPlan::Limit {
85 input,
86 count,
87 offset,
88 } => LogicalPlan::Limit {
89 input: Box::new(prune_projections(*input, required)),
90 count,
91 offset,
92 },
93 LogicalPlan::Join {
94 left,
95 right,
96 on,
97 join_type,
98 algo_hint,
99 } => LogicalPlan::Join {
100 left: Box::new(prune_projections(*left, required)),
101 right: Box::new(prune_projections(*right, required)),
102 on,
103 join_type,
104 algo_hint,
105 },
106 other => other,
107 }
108}