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