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 context: &SchemaDependencyBindingContext<'_>,
67 expression: &crate::ast::Expr,
68) -> Result<bool, String> {
69 if crate::type_resolution::composite_rows::expression_requires_binding(
70 expression,
71 context.schema,
72 )
73 .map_err(|error| error.to_string())?
74 {
75 return Ok(true);
76 }
77 let mut expression = expression.clone();
78 let mut legacy = false;
79 walk_schema_expr_mut(&mut expression, &mut |node| {
80 if let crate::ast::Expr::Func { binding, .. } = node {
81 legacy |= binding.as_ref().is_none_or(|binding| {
82 crate::binding::legacy_patterns::requires_binding(binding)
83 || !binding.builtin
84 && binding.dispatch.is_none()
85 && binding.resolution_error.is_none()
86 && binding.object_id.is_none()
87 });
88 }
89 Ok(())
90 })?;
91 Ok(legacy)
92}
93
94pub fn schema_expr_has_legacy_routine_identity(
95 expression: &crate::ast::Expr,
96) -> Result<bool, String> {
97 let mut expression = expression.clone();
98 let mut legacy = false;
99 walk_schema_expr_mut(&mut expression, &mut |node| {
100 if let crate::ast::Expr::Func {
101 binding: Some(binding),
102 ..
103 } = node
104 {
105 legacy |= !binding.builtin
106 && binding.dispatch.is_none()
107 && binding.resolution_error.is_none()
108 && binding.object_id.is_none();
109 }
110 Ok(())
111 })?;
112 Ok(legacy)
113}
114
115pub fn bind_table_schema_routine_identities(
116 context: &SchemaDependencyBindingContext<'_>,
117 table_name: &str,
118 columns: &mut [crate::ast::ColumnDef],
119 checks: &mut [crate::ast::TableCheck],
120) -> Result<bool, String> {
121 let check_columns = columns.to_vec();
122 bind_table_schema_routine_identities_with_check_columns(
123 context,
124 table_name,
125 columns,
126 checks,
127 &check_columns,
128 )
129}
130
131pub fn bind_table_schema_routine_identities_with_check_columns(
132 context: &SchemaDependencyBindingContext<'_>,
133 table_name: &str,
134 columns: &mut [crate::ast::ColumnDef],
135 checks: &mut [crate::ast::TableCheck],
136 check_columns: &[crate::ast::ColumnDef],
137) -> Result<bool, String> {
138 let mut changed = super::regclass::bind_table_schema_regclass_constants(
139 context.references,
140 columns,
141 checks,
142 false,
143 )?;
144 for column in columns {
145 if let Some(default) = &mut column.default {
146 changed |= bind_default_routine_identities(context, table_name, &column.name, default)?;
147 }
148 if let Some(check) = &mut column.check {
149 if schema_expr_may_require_routine_identity_binding(context, check)? {
150 changed |=
151 bind_check_routines(context, table_name, table_name, check_columns, check)
152 .map_err(|error| {
153 format!(
154 "bind CHECK routine identities for `{table_name}`.`{}`: {error}",
155 column.name
156 )
157 })?;
158 }
159 }
160 }
161 for check in checks {
162 if schema_expr_may_require_routine_identity_binding(context, &check.expr)? {
163 changed |= bind_check_routines(
164 context,
165 table_name,
166 table_name,
167 check_columns,
168 &mut check.expr,
169 )
170 .map_err(|error| {
171 format!("bind CHECK routine identities for `{table_name}`: {error}")
172 })?;
173 }
174 }
175 Ok(changed)
176}
177
178pub fn bind_default_routine_identities(
179 context: &SchemaDependencyBindingContext<'_>,
180 table_name: &str,
181 column_name: &str,
182 default: &mut crate::ast::Expr,
183) -> Result<bool, String> {
184 let changed =
185 super::regclass::bind_schema_regclass_constants(context.references, default, false)?;
186 if !schema_expr_may_require_routine_identity_binding(context, default)? {
187 return Ok(changed);
188 }
189 let bound = bind_default_routines(context, default, default.clone()).map_err(|error| {
190 format!("bind default routine identities for `{table_name}`.`{column_name}`: {error}")
191 })?;
192 Ok(changed || bound)
193}
194
195fn bind_check_routines(
196 context: &SchemaDependencyBindingContext<'_>,
197 table: &str,
198 qualifier: &str,
199 columns: &[ColumnDef],
200 expression: &mut Expr,
201) -> Result<bool, SQLError> {
202 let binding = context.bindings.binding_scope()?;
203 crate::schema::constraints::bind_stored_check_expression(
204 &SchemaBindingContext {
205 catalog: context.schema,
206 binding: &binding.context(),
207 },
208 table,
209 qualifier,
210 columns,
211 expression,
212 )
213}
214fn bind_default_routines(
215 context: &SchemaDependencyBindingContext<'_>,
216 expression: &mut Expr,
217 typed: Expr,
218) -> Result<bool, SQLError> {
219 let binding = context.bindings.binding_scope()?;
220 crate::schema::defaults::bind_stored_schema_expression(
221 &SchemaBindingContext {
222 catalog: context.schema,
223 binding: &binding.context(),
224 },
225 expression,
226 typed,
227 )
228}
229
230pub fn restore_legacy_default_sequence_inputs(
233 context: &SchemaDependencyBindingContext<'_>,
234 sequences: &dyn crate::schema::sequences::implicit_ownership::StoredSequenceNames,
235 columns: &mut [ColumnDef],
236) -> Result<bool, String> {
237 let mut changed = false;
238 for default in columns
239 .iter_mut()
240 .filter_map(|column| column.default.as_mut())
241 {
242 if super::regclass::bind_legacy_sequence_regclass_constants(
243 context.references,
244 sequences,
245 default,
246 )? {
247 bind_default_routines(context, default, default.clone())
248 .map_err(|error| error.to_string())?;
249 changed = true;
250 }
251 }
252 Ok(changed)
253}