Skip to main content

uqa_planner/explain/
physical.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Static physical diagnostics over the statement's retained catalog. No query operator is executed here.
8
9use crate::{
10    filter_pushdown::context::{FilterPushdownContext, FilterPushdownScope},
11    retrieval_planning::RetrievalPlanningCatalog,
12    statement_planning::PlannerStatisticsCatalog,
13};
14use std::{collections::BTreeMap, rc::Rc};
15use uqa_sql::{
16    plan::{CtePlan, UnifiedPlan},
17    result::ExplainPhysicalPlan,
18    retrieval::ConstantEvaluator,
19    SQLError, SQLParam,
20};
21
22mod query;
23mod source;
24mod vector;
25
26#[derive(Clone, Copy)]
27pub struct PhysicalExplainContext<'a> {
28    pub retrieval: &'a dyn RetrievalPlanningCatalog,
29    pub statistics: &'a dyn PlannerStatisticsCatalog,
30    pub filters: FilterPushdownContext<'a>,
31    pub evaluate: &'a ConstantEvaluator<'a>,
32}
33
34#[derive(Clone)]
35struct DeferredCte {
36    plan: CtePlan,
37    outer: Rc<Scope>,
38}
39type Scope = BTreeMap<String, Option<DeferredCte>>;
40
41pub fn physical_plan(
42    context: PhysicalExplainContext<'_>,
43    body: &UnifiedPlan,
44    params: &[SQLParam],
45) -> Result<ExplainPhysicalPlan, SQLError> {
46    let mut collector = Collector {
47        context,
48        params,
49        output: ExplainPhysicalPlan::default(),
50    };
51    collector.statement(body, &Scope::new(), "Statement")?;
52    Ok(collector.output)
53}
54
55struct Collector<'a> {
56    context: PhysicalExplainContext<'a>,
57    params: &'a [SQLParam],
58    output: ExplainPhysicalPlan,
59}
60
61impl Collector<'_> {
62    fn filter_scope<'a>(&'a self, visible: &'a dyn Fn(&str) -> bool) -> FilterPushdownScope<'a> {
63        FilterPushdownScope {
64            catalog: self.context.filters.correlation.catalog,
65            resolution: self.context.filters.correlation.resolution,
66            is_visible_cte: visible,
67        }
68    }
69}
70
71fn visible_cte(scope: &Scope, name: &str) -> bool {
72    uqa_sql::semantics::cte_reference_name(name).is_some_and(|name| scope.contains_key(&name))
73}