uqa_sql/schema/table_creation/
declaration.rs1use crate::ast::{ColumnDef, ColumnType, CreateTable, Expr};
9use crate::schema::constraints::validate_foreign_key_definition;
10use crate::schema::foreign_keys::{resolve_foreign_key_parent, ForeignKeyDefinitionContext};
11use crate::schema::indexes::names::IndexNameCatalog;
12use crate::schema::inheritance::InheritanceContext;
13use crate::schema::{SchemaBindingContext, SchemaExpressionCatalog};
14use crate::semantics::conflict::InferenceBindingScope;
15use crate::type_resolution::FunctionTypeResolver;
16use crate::SQLError;
17
18pub struct CreateTableAnalysisContext<'a> {
19 pub types: &'a dyn FunctionTypeResolver,
20 pub schema: &'a dyn SchemaExpressionCatalog,
21 pub bindings: &'a dyn InferenceBindingScope,
22 pub inheritance: InheritanceContext<'a>,
23 pub index_names: &'a dyn IndexNameCatalog,
24 pub foreign_keys: ForeignKeyDefinitionContext<'a>,
25}
26
27pub fn prepare_create_table_declaration(
28 context: &CreateTableAnalysisContext<'_>,
29 c: &mut CreateTable,
30) -> Result<(), SQLError> {
31 for column in &mut c.columns {
32 column.ty =
33 crate::type_resolution::resolve_declared_column_type(context.types, &column.ty)?;
34 }
35 super::super::inheritance::prepare_create_table_hierarchy(&context.inheritance, c)?;
36 super::super::indexes::names::name_constraint_indexes(
37 context.index_names,
38 &c.name,
39 &mut c.key_constraints,
40 )?;
41 bind_create_table_relation_references(context.foreign_keys.catalog, c)?;
42 Ok(())
43}
44
45pub fn validate_create_table_expressions(
46 context: &CreateTableAnalysisContext<'_>,
47 c: &mut CreateTable,
48) -> Result<(), SQLError> {
49 let check_columns = c.columns.clone();
50 for column in &mut c.columns {
51 if let Some(default) = &mut column.default {
52 validate_default_expression(context, default, &column.ty)?;
53 }
54 if let Some(check) = &mut column.check {
55 validate_check_expression(context, &c.name, &c.qualifier, &check_columns, check)?;
56 crate::catalog::regrole_dependencies::reject_stored_regrole_constants(
57 context.schema,
58 check,
59 None,
60 )?;
61 }
62 }
63 for check in &mut c.checks {
64 validate_check_expression(
65 context,
66 &c.name,
67 &c.qualifier,
68 &check_columns,
69 &mut check.expr,
70 )?;
71 crate::catalog::regrole_dependencies::reject_stored_regrole_constants(
72 context.schema,
73 &check.expr,
74 None,
75 )?;
76 }
77 super::super::check_inheritance::merge_create_checks(c)?;
78 for foreign_key in &mut c.foreign_keys {
79 if !foreign_key.period {
80 continue;
81 }
82 let self_reference = foreign_key.ref_table == c.name
83 || foreign_key.ref_table == c.qualifier
84 || c.name
85 .rsplit_once('.')
86 .is_some_and(|(_, local_name)| local_name == foreign_key.ref_table);
87 if self_reference {
88 validate_foreign_key_definition(
89 &c.name,
90 &c.columns,
91 &c.name,
92 &c.columns,
93 &c.key_constraints,
94 foreign_key,
95 )?;
96 foreign_key.ref_table.clone_from(&c.name);
97 } else {
98 let (canonical, parent_columns, parent_keys) =
99 resolve_foreign_key_parent(&context.foreign_keys, &foreign_key.ref_table)?;
100 validate_foreign_key_definition(
101 &c.name,
102 &c.columns,
103 &canonical,
104 &parent_columns,
105 &parent_keys,
106 foreign_key,
107 )?;
108 foreign_key.ref_table = canonical;
109 }
110 }
111 super::super::generated::prepare_generated_columns(
112 context.schema,
113 &c.qualifier,
114 &mut c.columns,
115 &c.key_constraints,
116 &c.foreign_keys,
117 )?;
118 Ok(())
119}
120
121pub fn bind_created_table_foreign_keys(
122 context: &ForeignKeyDefinitionContext<'_>,
123 c: &mut CreateTable,
124 registered_columns: &mut [ColumnDef],
125) -> Result<(), SQLError> {
126 let local_columns = registered_columns.to_vec();
127 for column in registered_columns {
128 let Some(reference) = column.references.clone() else {
129 continue;
130 };
131 let mut foreign_key = super::super::foreign_keys::column_foreign_key(column, &reference);
132 super::super::foreign_keys::validate_bound_foreign_key_definition_with_local_state(
133 context,
134 &c.name,
135 Some(&local_columns),
136 Some(&c.key_constraints),
137 &mut foreign_key,
138 )?;
139 let [referenced_column] = foreign_key.ref_columns.as_slice() else {
140 return Err(SQLError::Internal(
141 "column FOREIGN KEY did not resolve exactly one referenced column".into(),
142 ));
143 };
144 let Some(reference) = column.references.as_mut() else {
145 return Err(SQLError::Internal(
146 "column FOREIGN KEY disappeared during validation".into(),
147 ));
148 };
149 reference.referenced_key = foreign_key.referenced_key;
150 reference.referenced_index = foreign_key.referenced_index;
151 reference.table = foreign_key.ref_table;
152 reference.column = Some(referenced_column.clone());
153 }
154 for foreign_key in &mut c.foreign_keys {
155 super::super::foreign_keys::validate_bound_foreign_key_definition_with_local_state(
156 context,
157 &c.name,
158 Some(&local_columns),
159 Some(&c.key_constraints),
160 foreign_key,
161 )?;
162 }
163 Ok(())
164}
165
166fn validate_default_expression(
167 context: &CreateTableAnalysisContext<'_>,
168 expression: &mut Expr,
169 target: &ColumnType,
170) -> Result<(), SQLError> {
171 let binding = context.bindings.binding_scope()?;
172 super::super::defaults::validate_default_expression(
173 &SchemaBindingContext {
174 catalog: context.schema,
175 binding: &binding.context(),
176 },
177 expression,
178 target,
179 )
180}
181
182fn validate_check_expression(
183 context: &CreateTableAnalysisContext<'_>,
184 table: &str,
185 qualifier: &str,
186 columns: &[ColumnDef],
187 expression: &mut Expr,
188) -> Result<(), SQLError> {
189 let binding = context.bindings.binding_scope()?;
190 super::super::constraints::validate_check_expression(
191 &SchemaBindingContext {
192 catalog: context.schema,
193 binding: &binding.context(),
194 },
195 table,
196 qualifier,
197 columns,
198 expression,
199 )
200}
201
202fn bind_create_table_relation_references(
203 catalog: &dyn super::super::foreign_keys::ForeignKeyDefinitionCatalog,
204 table: &mut CreateTable,
205) -> Result<(), SQLError> {
206 let table_name = table.name.clone();
207 let qualifier = table.qualifier.clone();
208 for column in &mut table.columns {
209 if let Some(reference) = column.references.as_mut() {
210 bind_create_table_reference(catalog, &table_name, &qualifier, &mut reference.table)?;
211 }
212 }
213 for foreign_key in &mut table.foreign_keys {
214 bind_create_table_reference(catalog, &table_name, &qualifier, &mut foreign_key.ref_table)?;
215 }
216 Ok(())
217}
218
219fn bind_create_table_reference(
220 catalog: &dyn super::super::foreign_keys::ForeignKeyDefinitionCatalog,
221 table: &str,
222 qualifier: &str,
223 reference: &mut String,
224) -> Result<(), SQLError> {
225 let self_reference = reference == table
226 || reference == qualifier
227 || table
228 .rsplit_once('.')
229 .is_some_and(|(_, local_name)| local_name == reference);
230 if self_reference {
231 table.clone_into(reference);
232 return Ok(());
233 }
234 *reference = catalog.resolve_table_reference(reference)?;
235 Ok(())
236}