use crate::analyze::{ExprId, ExprIdLookup, StatementCategory};
use super::{
BindingTableSchema, ImplDefinedCaps, JoinTree, PatternPlan, PipelineOp, SubqueryRegistry,
};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(transparent)]
pub struct PipelineOpId(u32);
impl PipelineOpId {
pub(crate) const fn new(raw: u32) -> Self {
Self(raw)
}
#[must_use]
pub const fn get(self) -> u32 {
self.0
}
}
#[derive(Clone, Debug)]
pub struct ExecutionPlan {
pub category: StatementCategory,
pub pattern_plan: Option<PatternPlan>,
pub pipeline: Vec<PipelineOp>,
pub output_schema: BindingTableSchema,
pub impl_defined_caps: ImplDefinedCaps,
pub expr_ids: ExprIdLookup,
pub subqueries: SubqueryRegistry,
pub next_expr_id: ExprId,
pub next_pipeline_op_id: PipelineOpId,
}
impl ExecutionPlan {
pub(crate) fn alloc_expr_id(&mut self) -> ExprId {
let id = self.next_expr_id;
self.next_expr_id = ExprId::new(id.get().saturating_add(1));
id
}
pub(crate) fn refresh_pipeline_op_high_water(&mut self) {
if let Some(pattern) = &mut self.pattern_plan {
refresh_join_tree_pipeline_op_high_water(&mut pattern.join_tree);
}
for op in &mut self.pipeline {
match op {
PipelineOp::Union { rhs, .. }
| PipelineOp::Chain(rhs)
| PipelineOp::CorrelatedChain(rhs) => {
rhs.refresh_pipeline_op_high_water();
}
PipelineOp::CallSubquery(subquery) => {
subquery.body.refresh_pipeline_op_high_water();
}
PipelineOp::ExplainPlan { inner, .. } => inner.refresh_pipeline_op_high_water(),
_ => {}
}
}
self.next_pipeline_op_id = PipelineOpId::new(self.pipeline.len() as u32);
}
}
fn refresh_join_tree_pipeline_op_high_water(tree: &mut JoinTree) {
match tree {
JoinTree::Unit | JoinTree::Scan(_) => {}
JoinTree::Expand { child, .. }
| JoinTree::Questioned { child, .. }
| JoinTree::Repeat { child, .. }
| JoinTree::PathSearch { child, .. }
| JoinTree::PathModeFilter { child, .. }
| JoinTree::MatchModeFilter { child, .. } => {
refresh_join_tree_pipeline_op_high_water(child)
}
JoinTree::HashJoin { left, right, .. } | JoinTree::Outer { left, right, .. } => {
refresh_join_tree_pipeline_op_high_water(left);
refresh_join_tree_pipeline_op_high_water(right);
}
JoinTree::WorstCaseOptimal { intersection, .. } => {
for branch in intersection {
refresh_join_tree_pipeline_op_high_water(branch);
}
}
JoinTree::Subplan(plan) => plan.refresh_pipeline_op_high_water(),
JoinTree::DisjunctiveScan { .. } => {}
}
}