uqa_sql/semantics/rules/action_binding/
context.rs1use super::{apply_positional_aliases, cte_output_columns, BTreeMap, SQLError, CTE};
9use crate::ast::{ColumnType, Statement};
10
11pub trait RuleSourceCatalog {
12 fn query_source_columns(
13 &self,
14 name: &str,
15 relations_bound: bool,
16 ) -> Result<Option<Vec<String>>, SQLError>;
17 fn rule_relation_definitions(&self, name: &str)
18 -> Result<Vec<crate::ast::ColumnDef>, SQLError>;
19}
20
21#[derive(Clone, Default)]
22pub(super) struct RuleBindingContext<'a> {
23 pub(super) catalog: Option<&'a dyn RuleSourceCatalog>,
24 pub(super) relations_bound: bool,
25 pub(super) ctes: BTreeMap<String, Vec<String>>,
26}
27
28impl<'a> RuleBindingContext<'a> {
29 pub(super) fn with_catalog(catalog: &'a dyn RuleSourceCatalog, relations_bound: bool) -> Self {
30 Self {
31 catalog: Some(catalog),
32 relations_bound,
33 ctes: BTreeMap::new(),
34 }
35 }
36
37 pub(super) fn relation_columns(&self, name: &str) -> Result<Vec<String>, SQLError> {
38 if let Some(columns) = self.ctes.get(&name.to_ascii_lowercase()) {
39 return Ok(columns.clone());
40 }
41 self.catalog.map_or_else(
42 || Ok(Vec::new()),
43 |catalog| {
44 catalog
45 .query_source_columns(name, self.relations_bound)?
46 .ok_or_else(|| SQLError::UnknownTable(name.to_string()))
47 },
48 )
49 }
50
51 pub(super) fn with_ctes(&self, ctes: &[CTE]) -> Result<Self, SQLError> {
52 let mut context = self.clone();
53 for cte in ctes {
54 let key = cte.name.to_ascii_lowercase();
55 if cte.recursive {
56 context.ctes.entry(key.clone()).or_default();
57 }
58 let mut columns = cte_output_columns(&cte.body, &context)?;
59 apply_positional_aliases(&mut columns, &cte.columns);
60 if let Some(search) = &cte.search {
61 columns.push(search.sequence_column.clone());
62 }
63 if let Some(cycle) = &cte.cycle {
64 columns.push(cycle.mark_column.clone());
65 columns.push(cycle.path_column.clone());
66 }
67 context.ctes.insert(key, columns);
68 }
69 Ok(context)
70 }
71}
72
73pub fn rule_action_target_row_type(
74 catalog: &dyn RuleSourceCatalog,
75 action: &Statement,
76) -> Result<Vec<(String, ColumnType)>, SQLError> {
77 let table = match action {
78 Statement::Insert(statement) => &statement.table,
79 Statement::Update(statement) => &statement.table,
80 Statement::Delete(statement) => &statement.table,
81 _ => return Ok(Vec::new()),
82 };
83 Ok(catalog
84 .rule_relation_definitions(table)?
85 .into_iter()
86 .map(|column| (column.name, column.ty))
87 .collect())
88}
89pub fn rule_action_target_columns(
90 catalog: &dyn RuleSourceCatalog,
91 action: &Statement,
92) -> Result<std::collections::BTreeSet<String>, SQLError> {
93 Ok(rule_action_target_row_type(catalog, action)?
94 .into_iter()
95 .map(|(column, _)| column)
96 .collect())
97}