use crate::LogicalPlan;
use super::OptPass;
pub struct ProjectionPruning {
pub required: Vec<String>,
}
impl OptPass for ProjectionPruning {
fn name(&self) -> &'static str {
"ProjectionPruning"
}
fn apply(&self, plan: LogicalPlan) -> LogicalPlan {
if self.required.is_empty() {
return plan;
}
prune_projections(plan, &self.required)
}
}
pub(super) fn prune_projections(plan: LogicalPlan, required: &[String]) -> LogicalPlan {
match plan {
LogicalPlan::Project { input, columns } => {
let pruned: Vec<String> = columns
.into_iter()
.filter(|col| {
required
.iter()
.any(|r| col == r || col.contains(r.as_str()))
})
.collect();
let new_required = if pruned.is_empty() {
required.to_vec()
} else {
pruned.clone()
};
let final_cols = if pruned.is_empty() {
required.to_vec()
} else {
pruned
};
LogicalPlan::Project {
input: Box::new(prune_projections(*input, &new_required)),
columns: final_cols,
}
}
LogicalPlan::Filter { input, predicate } => LogicalPlan::Filter {
input: Box::new(prune_projections(*input, required)),
predicate,
},
LogicalPlan::Aggregate {
input,
group_by,
aggregates,
} => LogicalPlan::Aggregate {
input: Box::new(prune_projections(*input, required)),
group_by,
aggregates,
},
LogicalPlan::Sort { input, order_by } => LogicalPlan::Sort {
input: Box::new(prune_projections(*input, required)),
order_by,
},
LogicalPlan::Limit {
input,
count,
offset,
} => LogicalPlan::Limit {
input: Box::new(prune_projections(*input, required)),
count,
offset,
},
LogicalPlan::Join {
left,
right,
on,
join_type,
algo_hint,
} => LogicalPlan::Join {
left: Box::new(prune_projections(*left, required)),
right: Box::new(prune_projections(*right, required)),
on,
join_type,
algo_hint,
},
other => other,
}
}