uqa_sql/schema/dependencies/
registration.rs1use super::{regclass::SchemaReferenceCatalog, walk_schema_expr_mut};
9use crate::schema::{SchemaBindingContext, SchemaExpressionCatalog};
10use crate::semantics::conflict::InferenceBindingScope;
11use crate::{
12 ast::{ColumnDef, Expr},
13 SQLError,
14};
15
16pub struct SchemaDependencyBindingContext<'a> {
17 pub references: &'a dyn SchemaReferenceCatalog,
18 pub schema: &'a dyn SchemaExpressionCatalog,
19 pub bindings: &'a dyn InferenceBindingScope,
20}
21
22pub fn rewrite_schema_routine_references(
23 columns: &mut [crate::ast::ColumnDef],
24 checks: &mut [crate::ast::TableCheck],
25 target: &crate::ast::FunctionBinding,
26 new_name: &str,
27) -> Result<bool, String> {
28 let mut changed = false;
29 for column in columns {
30 for expression in [&mut column.default, &mut column.check]
31 .into_iter()
32 .flatten()
33 {
34 changed |= crate::catalog::stored_ast::rewrite_expression_routine_identity(
35 expression, target, new_name,
36 )
37 .map_err(|error| error.to_string())?;
38 }
39 if let Some(generated) = column.generated.as_mut() {
40 changed |= crate::catalog::stored_ast::rewrite_expression_routine_identity(
41 &mut generated.expression,
42 target,
43 new_name,
44 )
45 .map_err(|error| error.to_string())?;
46 for dependency in &mut generated.function_dependencies {
47 if crate::routines::function_binding_matches(dependency, target) {
48 dependency.name = new_name.to_string();
49 changed = true;
50 }
51 }
52 }
53 }
54 for check in checks {
55 changed |= crate::catalog::stored_ast::rewrite_expression_routine_identity(
56 &mut check.expr,
57 target,
58 new_name,
59 )
60 .map_err(|error| error.to_string())?;
61 }
62 Ok(changed)
63}
64
65fn schema_expr_may_require_routine_identity_binding(
66 expression: &crate::ast::Expr,
67) -> Result<bool, String> {
68 let mut expression = expression.clone();
69 let mut legacy = false;
70 walk_schema_expr_mut(&mut expression, &mut |node| {
71 if let crate::ast::Expr::Func { binding, .. } = node {
72 legacy |= binding.as_ref().is_none_or(|binding| {
73 !binding.builtin
74 && binding.dispatch.is_none()
75 && binding.resolution_error.is_none()
76 && binding.object_id.is_none()
77 });
78 }
79 Ok(())
80 })?;
81 Ok(legacy)
82}
83
84pub fn schema_expr_has_legacy_routine_identity(
85 expression: &crate::ast::Expr,
86) -> Result<bool, String> {
87 let mut expression = expression.clone();
88 let mut legacy = false;
89 walk_schema_expr_mut(&mut expression, &mut |node| {
90 if let crate::ast::Expr::Func {
91 binding: Some(binding),
92 ..
93 } = node
94 {
95 legacy |= !binding.builtin
96 && binding.dispatch.is_none()
97 && binding.resolution_error.is_none()
98 && binding.object_id.is_none();
99 }
100 Ok(())
101 })?;
102 Ok(legacy)
103}
104
105pub fn bind_table_schema_routine_identities(
106 context: &SchemaDependencyBindingContext<'_>,
107 table_name: &str,
108 columns: &mut [crate::ast::ColumnDef],
109 checks: &mut [crate::ast::TableCheck],
110) -> Result<bool, String> {
111 let check_columns = columns.to_vec();
112 bind_table_schema_routine_identities_with_check_columns(
113 context,
114 table_name,
115 columns,
116 checks,
117 &check_columns,
118 )
119}
120
121pub fn bind_table_schema_routine_identities_with_check_columns(
122 context: &SchemaDependencyBindingContext<'_>,
123 table_name: &str,
124 columns: &mut [crate::ast::ColumnDef],
125 checks: &mut [crate::ast::TableCheck],
126 check_columns: &[crate::ast::ColumnDef],
127) -> Result<bool, String> {
128 let mut changed = super::regclass::bind_table_schema_regclass_constants(
129 context.references,
130 columns,
131 checks,
132 false,
133 )?;
134 for column in columns {
135 if let Some(default) = &mut column.default {
136 changed |= bind_default_routine_identities(context, table_name, &column.name, default)?;
137 }
138 if let Some(check) = &mut column.check {
139 if schema_expr_may_require_routine_identity_binding(check)? {
140 changed |=
141 bind_check_routines(context, table_name, table_name, check_columns, check)
142 .map_err(|error| {
143 format!(
144 "bind CHECK routine identities for `{table_name}`.`{}`: {error}",
145 column.name
146 )
147 })?;
148 }
149 }
150 }
151 for check in checks {
152 if schema_expr_may_require_routine_identity_binding(&check.expr)? {
153 changed |= bind_check_routines(
154 context,
155 table_name,
156 table_name,
157 check_columns,
158 &mut check.expr,
159 )
160 .map_err(|error| {
161 format!("bind CHECK routine identities for `{table_name}`: {error}")
162 })?;
163 }
164 }
165 Ok(changed)
166}
167
168pub fn bind_default_routine_identities(
169 context: &SchemaDependencyBindingContext<'_>,
170 table_name: &str,
171 column_name: &str,
172 default: &mut crate::ast::Expr,
173) -> Result<bool, String> {
174 let changed =
175 super::regclass::bind_schema_regclass_constants(context.references, default, false)?;
176 if !schema_expr_may_require_routine_identity_binding(default)? {
177 return Ok(changed);
178 }
179 let bound = bind_default_routines(context, default, default.clone()).map_err(|error| {
180 format!("bind default routine identities for `{table_name}`.`{column_name}`: {error}")
181 })?;
182 Ok(changed || bound)
183}
184
185fn bind_check_routines(
186 context: &SchemaDependencyBindingContext<'_>,
187 table: &str,
188 qualifier: &str,
189 columns: &[ColumnDef],
190 expression: &mut Expr,
191) -> Result<bool, SQLError> {
192 let binding = context.bindings.binding_scope()?;
193 crate::schema::constraints::bind_stored_check_expression_routines(
194 &SchemaBindingContext {
195 catalog: context.schema,
196 binding: &binding.context(),
197 },
198 table,
199 qualifier,
200 columns,
201 expression,
202 )
203}
204fn bind_default_routines(
205 context: &SchemaDependencyBindingContext<'_>,
206 expression: &mut Expr,
207 typed: Expr,
208) -> Result<bool, SQLError> {
209 let binding = context.bindings.binding_scope()?;
210 crate::schema::defaults::bind_stored_schema_expression_routines(
211 &SchemaBindingContext {
212 catalog: context.schema,
213 binding: &binding.context(),
214 },
215 expression,
216 typed,
217 )
218}