uqa_sql/schema/sequences/dependencies/
analysis.rs1use super::super::{dependents::SequenceSchemaDependent, implicit_ownership::StoredSequenceNames};
9use crate::schema::dependencies::rewrites::rewrite_sequence_function_references;
10use std::{collections::BTreeMap, ops::Deref};
11use uqa_core::RelationIdentity;
12pub type SequenceExpressionObjectIdsRead<'a> =
13 Box<dyn Deref<Target = BTreeMap<RelationIdentity, [u8; 16]>> + 'a>;
14pub trait SequenceExpressionCatalog: StoredSequenceNames {
15 fn object_ids(&self) -> SequenceExpressionObjectIdsRead<'_>;
16}
17fn expression_references_sequence(
18 catalog: &dyn SequenceExpressionCatalog,
19 expression: Option<&crate::ast::Expr>,
20 sequence: &str,
21) -> Result<bool, String> {
22 expression.map_or(Ok(false), |expression| {
23 Ok(stored_sequence_targets_in_loaded_expr(catalog, expression)?.contains(sequence))
24 })
25}
26pub fn append_sequence_schema_expression_dependents(
27 catalog: &dyn SequenceExpressionCatalog,
28 table_name: &str,
29 columns: &[crate::ast::ColumnDef],
30 checks: &[crate::ast::TableCheck],
31 sequence: &str,
32 foreign: bool,
33 dependents: &mut Vec<SequenceSchemaDependent>,
34) -> Result<(), String> {
35 let relation = if foreign {
36 format!("foreign table `{table_name}`")
37 } else {
38 format!("`{table_name}`")
39 };
40 for column in columns {
41 if expression_references_sequence(catalog, column.default.as_ref(), sequence)? {
42 dependents.push(SequenceSchemaDependent::Default {
43 table: table_name.to_string(),
44 column: column.name.clone(),
45 foreign,
46 });
47 }
48 if expression_references_sequence(
49 catalog,
50 column
51 .generated
52 .as_ref()
53 .map(|generated| generated.expression.as_ref()),
54 sequence,
55 )? {
56 dependents.push(SequenceSchemaDependent::GeneratedColumn {
57 table: table_name.to_string(),
58 column: column.name.clone(),
59 foreign,
60 });
61 }
62 if expression_references_sequence(catalog, column.check.as_ref(), sequence)? {
63 dependents.push(SequenceSchemaDependent::CheckConstraint {
64 table: table_name.to_string(),
65 constraint: column.check_name.clone().ok_or_else(|| {
66 format!(
67 "CHECK constraint on {relation}.`{}` has no catalog name",
68 column.name
69 )
70 })?,
71 foreign,
72 });
73 }
74 }
75 for check in checks {
76 if expression_references_sequence(catalog, Some(&check.expr), sequence)? {
77 dependents.push(SequenceSchemaDependent::CheckConstraint {
78 table: table_name.to_string(),
79 constraint: check.name.clone().ok_or_else(|| {
80 format!("table CHECK constraint on {relation} has no catalog name")
81 })?,
82 foreign,
83 });
84 }
85 }
86 Ok(())
87}
88pub fn stored_sequence_targets_in_loaded_expr(
89 catalog: &dyn SequenceExpressionCatalog,
90 expression: &crate::ast::Expr,
91) -> Result<std::collections::BTreeSet<String>, String> {
92 let mut expression = expression.clone();
93 let mut targets = std::collections::BTreeSet::new();
94 rewrite_sequence_function_references(&mut expression, &mut |reference| {
95 let canonical = catalog.stored_sequence_name(reference)?;
96 targets.insert(canonical.clone());
97 *reference = canonical;
98 Ok(())
99 })?;
100 let identities = catalog
101 .object_ids()
102 .iter()
103 .map(|(name, id)| {
104 (
105 crate::catalog::oids::stable_object_oid("relation", id),
106 name.qualified_name(),
107 )
108 })
109 .collect::<std::collections::BTreeMap<_, _>>();
110 crate::schema::dependencies::walk_schema_expr_mut(&mut expression, &mut |node| {
111 if let Some(name) = crate::schema::dependencies::regclass::regclass_constant_oid(node)
112 .and_then(|oid| identities.get(&oid))
113 {
114 targets.insert(name.clone());
115 }
116 Ok(())
117 })?;
118 Ok(targets)
119}
120
121#[cfg(test)]
122mod tests;