risingwave_frontend/optimizer/rule/stream/
stream_project_merge_rule.rsuse crate::expr::{ExprImpl, ExprRewriter, ExprVisitor};
use crate::optimizer::plan_expr_visitor::InputRefCounter;
use crate::optimizer::plan_node::{generic, PlanTreeNodeUnary, StreamProject};
use crate::optimizer::rule::Rule;
use crate::optimizer::{BoxedRule, PlanRef};
use crate::utils::Substitute;
pub struct StreamProjectMergeRule {}
impl Rule for StreamProjectMergeRule {
fn apply(&self, plan: PlanRef) -> Option<PlanRef> {
let outer_project = plan.as_stream_project()?;
let input = outer_project.input();
let inner_project = input.as_stream_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());
let noop_update_hint = outer_project.noop_update_hint() || inner_project.noop_update_hint();
Some(
StreamProject::new(logical_project)
.with_noop_update_hint(noop_update_hint)
.into(),
)
}
}
impl StreamProjectMergeRule {
pub fn create() -> BoxedRule {
Box::new(StreamProjectMergeRule {})
}
}