risingwave_frontend/optimizer/rule/batch/
batch_project_merge_rule.rs1use crate::expr::{ExprImpl, ExprRewriter, ExprVisitor};
16use crate::optimizer::plan_expr_visitor::InputRefCounter;
17use crate::optimizer::plan_node::{BatchProject, PlanTreeNodeUnary, generic};
18use crate::optimizer::rule::Rule;
19use crate::optimizer::{BoxedRule, PlanRef};
20use crate::utils::Substitute;
21
22pub struct BatchProjectMergeRule {}
24impl Rule for BatchProjectMergeRule {
25 fn apply(&self, plan: PlanRef) -> Option<PlanRef> {
26 let outer_project = plan.as_batch_project()?;
27 let input = outer_project.input();
28 let inner_project = input.as_batch_project()?;
29
30 let mut input_ref_counter = InputRefCounter::default();
31 for expr in outer_project.exprs() {
32 input_ref_counter.visit_expr(expr);
33 }
34 for (index, count) in &input_ref_counter.counter {
36 if *count > 1 && matches!(inner_project.exprs()[*index], ExprImpl::FunctionCall(_)) {
37 return None;
38 }
39 }
40
41 let mut subst = Substitute {
42 mapping: inner_project.exprs().clone(),
43 };
44 let exprs = outer_project
45 .exprs()
46 .iter()
47 .cloned()
48 .map(|expr| subst.rewrite_expr(expr))
49 .collect();
50 let logical_project = generic::Project::new(exprs, inner_project.input());
51 Some(BatchProject::new(logical_project).into())
52 }
53}
54
55impl BatchProjectMergeRule {
56 pub fn create() -> BoxedRule {
57 Box::new(BatchProjectMergeRule {})
58 }
59}