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