Skip to main content

nodedb_sql/planner/
catalog_plan_shapes.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Catalog folding for reusable projection, ordering, aggregate, and window shapes.
4
5use nodedb_types::DatabaseId;
6
7use crate::catalog::SqlCatalog;
8use crate::types::{AggregateExpr, Projection, SortKey, SqlExpr, WindowSpec};
9
10use super::catalog_expr_fold::{fold_expr, validate_expr};
11
12pub(super) fn validate_projection(
13    projection: &[Projection],
14    catalog: &dyn SqlCatalog,
15    database_id: DatabaseId,
16    tenant_id: u64,
17) -> crate::Result<()> {
18    for item in projection {
19        match item {
20            Projection::Computed { expr, .. } | Projection::CpComputed { expr, .. } => {
21                validate_expr(expr, catalog, database_id, tenant_id)?;
22            }
23            Projection::Column(_) | Projection::Star | Projection::QualifiedStar(_) => {}
24        }
25    }
26    Ok(())
27}
28
29pub(super) fn validate_sort_keys(
30    sort_keys: &[SortKey],
31    catalog: &dyn SqlCatalog,
32    database_id: DatabaseId,
33    tenant_id: u64,
34) -> crate::Result<()> {
35    for key in sort_keys {
36        validate_expr(&key.expr, catalog, database_id, tenant_id)?;
37    }
38    Ok(())
39}
40
41pub(super) fn validate_aggregates(
42    aggregates: &[AggregateExpr],
43    catalog: &dyn SqlCatalog,
44    database_id: DatabaseId,
45    tenant_id: u64,
46) -> crate::Result<()> {
47    for aggregate in aggregates {
48        for arg in &aggregate.args {
49            validate_expr(arg, catalog, database_id, tenant_id)?;
50        }
51    }
52    Ok(())
53}
54
55pub(super) fn validate_windows(
56    windows: &[WindowSpec],
57    catalog: &dyn SqlCatalog,
58    database_id: DatabaseId,
59    tenant_id: u64,
60) -> crate::Result<()> {
61    for window in windows {
62        for expr in window.args.iter().chain(&window.partition_by) {
63            validate_expr(expr, catalog, database_id, tenant_id)?;
64        }
65        validate_sort_keys(&window.order_by, catalog, database_id, tenant_id)?;
66    }
67    Ok(())
68}
69
70pub(super) fn fold_projection(
71    projection: &mut [Projection],
72    catalog: &dyn SqlCatalog,
73    database_id: DatabaseId,
74    tenant_id: u64,
75) {
76    // The fold resolves catalog casts (`regclass`, `regtype`) only; a
77    // sequence accessor in a Control-Plane-computed item stays a call.
78    for item in projection {
79        match item {
80            Projection::Computed { expr, .. } | Projection::CpComputed { expr, .. } => {
81                let owned = std::mem::replace(expr, SqlExpr::Wildcard);
82                *expr = fold_expr(owned, catalog, database_id, tenant_id);
83            }
84            Projection::Column(_) | Projection::Star | Projection::QualifiedStar(_) => {}
85        }
86    }
87}
88
89pub(super) fn fold_sort_keys(
90    sort_keys: &mut [SortKey],
91    catalog: &dyn SqlCatalog,
92    database_id: DatabaseId,
93    tenant_id: u64,
94) {
95    for key in sort_keys {
96        let owned = std::mem::replace(&mut key.expr, SqlExpr::Wildcard);
97        key.expr = fold_expr(owned, catalog, database_id, tenant_id);
98    }
99}
100
101pub(super) fn fold_aggregates(
102    aggregates: &mut [AggregateExpr],
103    catalog: &dyn SqlCatalog,
104    database_id: DatabaseId,
105    tenant_id: u64,
106) {
107    for aggregate in aggregates {
108        for arg in &mut aggregate.args {
109            let owned = std::mem::replace(arg, SqlExpr::Wildcard);
110            *arg = fold_expr(owned, catalog, database_id, tenant_id);
111        }
112    }
113}
114
115pub(super) fn fold_windows(
116    windows: &mut [WindowSpec],
117    catalog: &dyn SqlCatalog,
118    database_id: DatabaseId,
119    tenant_id: u64,
120) {
121    for window in windows {
122        for expr in window.args.iter_mut().chain(&mut window.partition_by) {
123            let owned = std::mem::replace(expr, SqlExpr::Wildcard);
124            *expr = fold_expr(owned, catalog, database_id, tenant_id);
125        }
126        fold_sort_keys(&mut window.order_by, catalog, database_id, tenant_id);
127    }
128}