risingwave_frontend/optimizer/plan_visitor/
apply_visitor.rsuse super::{DefaultBehavior, Merge};
use crate::error::{ErrorCode, RwError};
use crate::optimizer::plan_node::{LogicalApply, PlanTreeNodeBinary};
use crate::optimizer::plan_visitor::PlanVisitor;
use crate::PlanRef;
pub struct HasMaxOneRowApply();
impl PlanVisitor for HasMaxOneRowApply {
type Result = bool;
type DefaultBehavior = impl DefaultBehavior<Self::Result>;
fn default_behavior() -> Self::DefaultBehavior {
Merge(|a, b| a | b)
}
fn visit_logical_apply(&mut self, plan: &LogicalApply) -> bool {
plan.max_one_row() | self.visit(plan.left()) | self.visit(plan.right())
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
enum CheckResult {
#[default]
Ok,
CannotBeUnnested,
MoreThanOneRow,
}
impl From<CheckResult> for Result<(), RwError> {
fn from(val: CheckResult) -> Self {
let msg = match val {
CheckResult::Ok => return Ok(()),
CheckResult::CannotBeUnnested => "Subquery can not be unnested.",
CheckResult::MoreThanOneRow => "Scalar subquery might produce more than one row.",
};
Err(ErrorCode::InternalError(msg.to_owned()).into())
}
}
#[derive(Default)]
pub struct CheckApplyElimination {
result: CheckResult,
}
impl PlanVisitor for CheckApplyElimination {
type Result = ();
type DefaultBehavior = impl DefaultBehavior<Self::Result>;
fn default_behavior() -> Self::DefaultBehavior {
Merge(std::cmp::max)
}
fn visit_logical_apply(&mut self, plan: &LogicalApply) {
if plan.right().as_logical_max_one_row().is_some() {
self.result = CheckResult::MoreThanOneRow;
} else {
self.result = CheckResult::CannotBeUnnested;
}
}
}
#[easy_ext::ext(PlanCheckApplyEliminationExt)]
impl PlanRef {
pub fn check_apply_elimination(&self) -> Result<(), RwError> {
let mut visitor = CheckApplyElimination::default();
visitor.visit(self.clone());
visitor.result.into()
}
}