risingwave_frontend/optimizer/rule/batch/
batch_project_merge_rule.rsuse crate::expr::{ExprImpl, ExprRewriter, ExprVisitor};
use crate::optimizer::plan_expr_visitor::InputRefCounter;
use crate::optimizer::plan_node::{generic, BatchProject, PlanTreeNodeUnary};
use crate::optimizer::rule::Rule;
use crate::optimizer::{BoxedRule, PlanRef};
use crate::utils::Substitute;
pub struct BatchProjectMergeRule {}
impl Rule for BatchProjectMergeRule {
fn apply(&self, plan: PlanRef) -> Option<PlanRef> {
let outer_project = plan.as_batch_project()?;
let input = outer_project.input();
let inner_project = input.as_batch_project()?;
let mut input_ref_counter = InputRefCounter::default();
for expr in outer_project.exprs() {
input_ref_counter.visit_expr(expr);
}
for (index, count) in &input_ref_counter.counter {
if *count > 1 && matches!(inner_project.exprs()[*index], ExprImpl::FunctionCall(_)) {
return None;
}
}
let mut subst = Substitute {
mapping: inner_project.exprs().clone(),
};
let exprs = outer_project
.exprs()
.iter()
.cloned()
.map(|expr| subst.rewrite_expr(expr))
.collect();
let logical_project = generic::Project::new(exprs, inner_project.input());
Some(BatchProject::new(logical_project).into())
}
}
impl BatchProjectMergeRule {
pub fn create() -> BoxedRule {
Box::new(BatchProjectMergeRule {})
}
}