Skip to main content

uqa_sql/binding/stored_columns/
lifecycle.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Stored statement and rewrite-rule column dependency entry points.
8
9use super::{
10    BTreeSet, ColumnBindingContext, ColumnBindingMode, Expr, RelationIdentity,
11    RuleColumnDependency, SQLError, Statement, StoredColumnBinder, StoredColumnBindingContext,
12};
13
14pub fn bind_stored_statement_source_columns(
15    statement: &mut Statement,
16    mut source_columns: impl FnMut(&str) -> Result<Option<Vec<String>>, SQLError>,
17) -> Result<bool, SQLError> {
18    let mut changed = false;
19    crate::catalog::stored_ast::visit_stored_statement_sources(statement, &mut |source| {
20        let crate::ast::FromClause::Table {
21            name,
22            bound_columns,
23            ..
24        } = source
25        else {
26            return Ok(());
27        };
28        if bound_columns.is_some() {
29            return Ok(());
30        }
31        *bound_columns = source_columns(name)?;
32        changed |= bound_columns.is_some();
33        Ok(())
34    })?;
35    Ok(changed)
36}
37
38pub fn remove_stored_statement_source_column_aliases(
39    catalog: StoredColumnBindingContext<'_>,
40    statement: &mut Statement,
41    dependencies: &BTreeSet<RuleColumnDependency>,
42) -> Result<bool, SQLError> {
43    let mut planned = statement.clone();
44    let mut binder = StoredColumnBinder::new(catalog, ColumnBindingMode::Drop { dependencies });
45    binder.bind_statement(&mut planned, &[], &ColumnBindingContext::default())?;
46    let changed = binder.alias_shape_changed();
47    if changed {
48        crate::catalog::stored_ast::copy_stored_source_column_shapes(&mut planned, statement)?;
49    }
50    Ok(changed)
51}
52
53pub fn stored_statement_column_dependencies(
54    catalog: StoredColumnBindingContext<'_>,
55    statement: &Statement,
56) -> Result<BTreeSet<RuleColumnDependency>, SQLError> {
57    bind_rule_action_column_dependencies(catalog, &mut statement.clone())
58}
59
60/// The column references of a stored statement: the relation columns its range tables provide, and the names that none provides, which a SQL routine body resolves as its parameters.
61#[derive(Debug, Clone, Default)]
62pub struct StoredStatementColumns {
63    pub dependencies: BTreeSet<RuleColumnDependency>,
64    /// Unresolved references by qualifier and name, in the order the statement names them.
65    pub unresolved: Vec<(Option<String>, String)>,
66}
67
68pub fn stored_statement_references(
69    catalog: StoredColumnBindingContext<'_>,
70    statement: &Statement,
71) -> Result<StoredStatementColumns, SQLError> {
72    let mut binder = StoredColumnBinder::new(catalog, ColumnBindingMode::Bind);
73    binder.bind_statement(
74        &mut statement.clone(),
75        &[],
76        &ColumnBindingContext::default(),
77    )?;
78    Ok(StoredStatementColumns {
79        dependencies: binder.dependencies,
80        unresolved: binder.unresolved,
81    })
82}
83
84pub fn bind_rule_condition_column_dependencies(
85    catalog: StoredColumnBindingContext<'_>,
86    condition: &mut Expr,
87) -> Result<BTreeSet<RuleColumnDependency>, SQLError> {
88    let mut binder = StoredColumnBinder::new(catalog, ColumnBindingMode::Bind);
89    binder.bind_expr(condition, &[], &ColumnBindingContext::default())?;
90    Ok(binder.finish())
91}
92
93pub fn bind_rule_action_column_dependencies(
94    catalog: StoredColumnBindingContext<'_>,
95    action: &mut Statement,
96) -> Result<BTreeSet<RuleColumnDependency>, SQLError> {
97    let mut binder = StoredColumnBinder::new(catalog, ColumnBindingMode::Bind);
98    binder.bind_statement(action, &[], &ColumnBindingContext::default())?;
99    Ok(binder.finish())
100}
101
102pub fn rewrite_rule_column_references(
103    catalog: StoredColumnBindingContext<'_>,
104    definition: &mut crate::ast::CreateRule,
105    relation: &RelationIdentity,
106    from: &str,
107    to: &str,
108) -> Result<(), SQLError> {
109    let mode = ColumnBindingMode::Rename { relation, from, to };
110    if let Some(condition) = &mut definition.condition {
111        let mut binder = StoredColumnBinder::new(catalog, mode);
112        binder.bind_expr(condition, &[], &ColumnBindingContext::default())?;
113    }
114    for action in &mut definition.actions {
115        let mut binder = StoredColumnBinder::new(catalog, mode);
116        binder.bind_statement(action, &[], &ColumnBindingContext::default())?;
117    }
118    Ok(())
119}
120
121pub fn remove_rule_source_column_aliases(
122    catalog: StoredColumnBindingContext<'_>,
123    definition: &mut crate::ast::CreateRule,
124    dependency: &RuleColumnDependency,
125) -> Result<bool, SQLError> {
126    let dependencies = BTreeSet::from([dependency.clone()]);
127    let mode = ColumnBindingMode::Drop {
128        dependencies: &dependencies,
129    };
130    let mut changed = false;
131    if let Some(condition) = &mut definition.condition {
132        let mut binder = StoredColumnBinder::new(catalog, mode);
133        binder.bind_expr(condition, &[], &ColumnBindingContext::default())?;
134        changed |= binder.alias_shape_changed();
135    }
136    for action in &mut definition.actions {
137        let mut binder = StoredColumnBinder::new(catalog, mode);
138        binder.bind_statement(action, &[], &ColumnBindingContext::default())?;
139        changed |= binder.alias_shape_changed();
140    }
141    Ok(changed)
142}