uqa_sql/schema/dependencies/
rewrites.rs1use super::walk_schema_expr_mut;
9use uqa_core::{RelationIdentity, Value};
10
11pub fn stored_relation_reference_matches(reference: &str, target: &RelationIdentity) -> bool {
12 match RelationIdentity::parse_reference(reference) {
13 Ok((Some(schema), name)) => schema == target.schema && name == target.name,
14 Ok((None, name)) => name == target.name,
15 Err(_) => true,
17 }
18}
19
20pub fn upgrade_legacy_schema_function_dispatches(
21 columns: &mut [crate::ast::ColumnDef],
22 constraints: &mut crate::ast::TableConstraintSet,
23) -> bool {
24 let mut changed = false;
25 for column in columns {
26 for expression in [column.default.as_mut(), column.check.as_mut()]
27 .into_iter()
28 .flatten()
29 {
30 changed |= expression.upgrade_legacy_serialized_dispatches();
31 }
32 if let Some(generated) = &mut column.generated {
33 changed |= generated.expression.upgrade_legacy_serialized_dispatches();
34 }
35 }
36 for check in &mut constraints.checks {
37 changed |= check.expr.upgrade_legacy_serialized_dispatches();
38 }
39 changed
40}
41
42pub fn rewrite_sequence_function_references(
43 expression: &mut crate::ast::Expr,
44 visit: &mut impl FnMut(&mut String) -> Result<(), String>,
45) -> Result<(), String> {
46 walk_schema_expr_mut(expression, &mut |node| {
47 let crate::ast::Expr::Func {
48 name,
49 binding,
50 args,
51 ..
52 } = node
53 else {
54 return Ok(());
55 };
56 if !is_sequence_function(name, binding.as_ref()) {
57 return Ok(());
58 }
59 let Some(reference) = args.first_mut().and_then(regclass_literal_mut) else {
60 return Ok(());
62 };
63 visit(reference)
64 })
65}
66
67pub(super) fn is_sequence_function(
68 name: &str,
69 binding: Option<&crate::ast::FunctionBinding>,
70) -> bool {
71 let name = if let Some(binding) = binding {
72 if !binding.builtin
73 || binding.object_id.is_some()
74 || binding.dispatch.is_some()
75 || binding.resolution_error.is_some()
76 {
77 return false;
78 }
79 &binding.name
80 } else {
81 name
82 };
83 let lower = name.to_ascii_lowercase();
84 let local = lower.strip_prefix("pg_catalog.").unwrap_or(&lower);
85 matches!(local, "nextval" | "currval" | "setval")
86}
87
88fn regclass_literal_mut(expression: &mut crate::ast::Expr) -> Option<&mut String> {
89 match expression {
90 crate::ast::Expr::Literal(Value::Str(reference)) => Some(reference),
91 crate::ast::Expr::Cast { expr, ty, .. }
92 if ty.eq_ignore_ascii_case("regclass")
93 || ty.eq_ignore_ascii_case("pg_catalog.regclass") =>
94 {
95 regclass_literal_mut(expr)
96 }
97 _ => None,
98 }
99}
100
101pub fn rename_schema_expr_column(
102 expression: &mut crate::ast::Expr,
103 from: &str,
104 to: &str,
105) -> Result<(), String> {
106 walk_schema_expr_mut(expression, &mut |node| {
107 match node {
108 crate::ast::Expr::Star | crate::ast::Expr::QualifiedStar(_) => {
109 return Err("schema expression contains `*` and cannot be rewritten safely".into());
110 }
111 crate::ast::Expr::Column(name) if name == from => *name = to.to_string(),
112 crate::ast::Expr::QualifiedColumn { column, .. } if column == from => {
113 *column = to.to_string();
114 }
115 _ => {}
116 }
117 Ok(())
118 })
119}
120
121pub fn schema_expr_references_relation(
122 expression: &crate::ast::Expr,
123 target: &RelationIdentity,
124) -> bool {
125 let mut expression = expression.clone();
126 let mut referenced = false;
127 let result = walk_schema_expr_mut(&mut expression, &mut |node| {
128 if let crate::ast::Expr::QualifiedColumn { qualifier, .. } = node {
129 referenced |= stored_relation_reference_matches(qualifier, target);
130 }
131 Ok(())
132 });
133 result.is_err() || referenced
134}
135
136pub fn rename_schema_expr_relation(
137 expression: &mut crate::ast::Expr,
138 from: &RelationIdentity,
139 to: &str,
140) -> Result<(), String> {
141 walk_schema_expr_mut(expression, &mut |node| {
142 if let crate::ast::Expr::QualifiedColumn { qualifier, .. } = node {
143 if stored_relation_reference_matches(qualifier, from) {
144 *qualifier = to.to_string();
145 }
146 }
147 Ok(())
148 })
149}
150
151pub fn rename_schema_expr_qualified_column(
152 expression: &mut crate::ast::Expr,
153 table: &RelationIdentity,
154 from: &str,
155 to: &str,
156) -> Result<(), String> {
157 walk_schema_expr_mut(expression, &mut |node| {
158 if let crate::ast::Expr::QualifiedColumn { qualifier, column } = node {
159 if column == from && stored_relation_reference_matches(qualifier, table) {
160 *column = to.to_string();
161 }
162 }
163 Ok(())
164 })
165}
166
167#[cfg(test)]
168mod tests;