Skip to main content

uqa_sql/semantics/
cte_strategy.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Shared CTE scheduling decisions for execution and traversal analysis.
8
9use crate::{
10    ast::CteMaterialization,
11    plan::{CtePlan, QueryPlan},
12    semantics::{
13        cte_references_own_name, ordered_plan_ctes, reachable_plan_cte_names,
14        single_reference_plan_cte_names,
15        volatility::{query_contains_volatile_function, VolatilityCatalog},
16    },
17    SQLError,
18};
19
20pub struct ScheduledCte<'a> {
21    pub plan: &'a CtePlan,
22    pub deferred: bool,
23}
24
25pub fn schedule_plan_ctes<'a>(
26    catalog: &dyn VolatilityCatalog,
27    plan: &'a QueryPlan,
28) -> Result<Vec<ScheduledCte<'a>>, SQLError> {
29    let ordered = ordered_plan_ctes(plan)?;
30    let reachable = reachable_plan_cte_names(plan);
31    let single_reference = single_reference_plan_cte_names(plan);
32    Ok(ordered
33        .into_iter()
34        .filter(|cte| reachable.contains(&cte.name))
35        .map(|cte| ScheduledCte {
36            plan: cte,
37            deferred: !cte.body.modifies_data()
38                && !cte_references_own_name(cte)
39                && match cte.materialization {
40                    CteMaterialization::Default => single_reference.contains(&cte.name),
41                    CteMaterialization::Materialized => false,
42                    CteMaterialization::NotMaterialized => true,
43                }
44                && matches!(
45                    cte.body
46                        .query()
47                        .map_or(Ok(true), |query| query_contains_volatile_function(
48                            catalog, query
49                        )),
50                    Ok(false)
51                ),
52        })
53        .collect())
54}