risingwave_frontend/optimizer/rule/
project_merge_rule.rs1use super::super::plan_node::*;
16use super::{BoxedRule, Rule};
17use crate::expr::{ExprImpl, ExprRewriter, ExprVisitor};
18use crate::optimizer::plan_expr_visitor::InputRefCounter;
19use crate::utils::Substitute;
20
21pub struct ProjectMergeRule {}
23impl Rule for ProjectMergeRule {
24 fn apply(&self, plan: PlanRef) -> Option<PlanRef> {
25 let outer_project: &LogicalProject = plan.as_logical_project()?;
26 let input = outer_project.input();
27 let inner_project: &LogicalProject = input.as_logical_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 subst = Substitute {
41 mapping: inner_project.exprs().clone(),
42 };
43 let exprs = outer_project
44 .exprs()
45 .iter()
46 .cloned()
47 .map(|expr| subst.rewrite_expr(expr))
48 .collect();
49 Some(LogicalProject::new(inner_project.input(), exprs).into())
50 }
51}
52
53impl ProjectMergeRule {
54 pub fn create() -> BoxedRule {
55 Box::new(ProjectMergeRule {})
56 }
57}