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 { name, args, .. } = node else {
48 return Ok(());
49 };
50 let lower = name.to_ascii_lowercase();
51 let local = lower.strip_prefix("pg_catalog.").unwrap_or(&lower);
52 if !matches!(local, "nextval" | "currval" | "setval")
53 || (lower.contains('.') && !lower.starts_with("pg_catalog."))
54 {
55 return Ok(());
56 }
57 let Some(reference) = args.first_mut().and_then(regclass_literal_mut) else {
58 return Ok(());
60 };
61 visit(reference)
62 })
63}
64
65fn regclass_literal_mut(expression: &mut crate::ast::Expr) -> Option<&mut String> {
66 match expression {
67 crate::ast::Expr::Literal(Value::Str(reference)) => Some(reference),
68 crate::ast::Expr::Cast { expr, ty }
69 if ty.eq_ignore_ascii_case("regclass")
70 || ty.eq_ignore_ascii_case("pg_catalog.regclass") =>
71 {
72 regclass_literal_mut(expr)
73 }
74 _ => None,
75 }
76}
77
78pub fn rename_schema_expr_column(
79 expression: &mut crate::ast::Expr,
80 from: &str,
81 to: &str,
82) -> Result<(), String> {
83 walk_schema_expr_mut(expression, &mut |node| {
84 match node {
85 crate::ast::Expr::Star | crate::ast::Expr::QualifiedStar(_) => {
86 return Err("schema expression contains `*` and cannot be rewritten safely".into());
87 }
88 crate::ast::Expr::Column(name) if name == from => *name = to.to_string(),
89 crate::ast::Expr::QualifiedColumn { column, .. } if column == from => {
90 *column = to.to_string();
91 }
92 _ => {}
93 }
94 Ok(())
95 })
96}
97
98pub fn schema_expr_references_relation(
99 expression: &crate::ast::Expr,
100 target: &RelationIdentity,
101) -> bool {
102 let mut expression = expression.clone();
103 let mut referenced = false;
104 let result = walk_schema_expr_mut(&mut expression, &mut |node| {
105 if let crate::ast::Expr::QualifiedColumn { qualifier, .. } = node {
106 referenced |= stored_relation_reference_matches(qualifier, target);
107 }
108 Ok(())
109 });
110 result.is_err() || referenced
111}
112
113pub fn rename_schema_expr_relation(
114 expression: &mut crate::ast::Expr,
115 from: &RelationIdentity,
116 to: &str,
117) -> Result<(), String> {
118 walk_schema_expr_mut(expression, &mut |node| {
119 if let crate::ast::Expr::QualifiedColumn { qualifier, .. } = node {
120 if stored_relation_reference_matches(qualifier, from) {
121 *qualifier = to.to_string();
122 }
123 }
124 Ok(())
125 })
126}
127
128pub fn rename_schema_expr_qualified_column(
129 expression: &mut crate::ast::Expr,
130 table: &RelationIdentity,
131 from: &str,
132 to: &str,
133) -> Result<(), String> {
134 walk_schema_expr_mut(expression, &mut |node| {
135 if let crate::ast::Expr::QualifiedColumn { qualifier, column } = node {
136 if column == from && stored_relation_reference_matches(qualifier, table) {
137 *column = to.to_string();
138 }
139 }
140 Ok(())
141 })
142}
143
144#[cfg(test)]
145mod tests;