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 for column in registered_columns {
127 let Some(reference) = column.references.clone() else {
128 continue;
129 };
130 let mut foreign_key = super::super::foreign_keys::column_foreign_key(column, &reference);
131 super::super::foreign_keys::validate_bound_foreign_key_definition_with_local_state(
132 context,
133 &c.name,
134 None,
135 Some(&c.key_constraints),
136 &mut foreign_key,
137 )?;
138 let [referenced_column] = foreign_key.ref_columns.as_slice() else {
139 return Err(SQLError::Internal(
140 "column FOREIGN KEY did not resolve exactly one referenced column".into(),
141 ));
142 };
143 let Some(reference) = column.references.as_mut() else {
144 return Err(SQLError::Internal(
145 "column FOREIGN KEY disappeared during validation".into(),
146 ));
147 };
148 reference.referenced_key = foreign_key.referenced_key;
149 reference.table = foreign_key.ref_table;
150 reference.column = Some(referenced_column.clone());
151 }
152 for foreign_key in &mut c.foreign_keys {
153 super::super::foreign_keys::validate_bound_foreign_key_definition_with_local_state(
154 context,
155 &c.name,
156 None,
157 Some(&c.key_constraints),
158 foreign_key,
159 )?;
160 }
161 Ok(())
162}
163
164fn validate_default_expression(
165 context: &CreateTableAnalysisContext<'_>,
166 expression: &mut Expr,
167 target: &ColumnType,
168) -> Result<(), SQLError> {
169 let binding = context.bindings.binding_scope()?;
170 super::super::defaults::validate_default_expression(
171 &SchemaBindingContext {
172 catalog: context.schema,
173 binding: &binding.context(),
174 },
175 expression,
176 target,
177 )
178}
179
180fn validate_check_expression(
181 context: &CreateTableAnalysisContext<'_>,
182 table: &str,
183 qualifier: &str,
184 columns: &[ColumnDef],
185 expression: &mut Expr,
186) -> Result<(), SQLError> {
187 let binding = context.bindings.binding_scope()?;
188 super::super::constraints::validate_check_expression(
189 &SchemaBindingContext {
190 catalog: context.schema,
191 binding: &binding.context(),
192 },
193 table,
194 qualifier,
195 columns,
196 expression,
197 )
198}
199
200fn bind_create_table_relation_references(
201 catalog: &dyn super::super::foreign_keys::ForeignKeyDefinitionCatalog,
202 table: &mut CreateTable,
203) -> Result<(), SQLError> {
204 let table_name = table.name.clone();
205 let qualifier = table.qualifier.clone();
206 for column in &mut table.columns {
207 if let Some(reference) = column.references.as_mut() {
208 bind_create_table_reference(catalog, &table_name, &qualifier, &mut reference.table)?;
209 }
210 }
211 for foreign_key in &mut table.foreign_keys {
212 bind_create_table_reference(catalog, &table_name, &qualifier, &mut foreign_key.ref_table)?;
213 }
214 Ok(())
215}
216
217fn bind_create_table_reference(
218 catalog: &dyn super::super::foreign_keys::ForeignKeyDefinitionCatalog,
219 table: &str,
220 qualifier: &str,
221 reference: &mut String,
222) -> Result<(), SQLError> {
223 let self_reference = reference == table
224 || reference == qualifier
225 || table
226 .rsplit_once('.')
227 .is_some_and(|(_, local_name)| local_name == reference);
228 if self_reference {
229 table.clone_into(reference);
230 return Ok(());
231 }
232 *reference = catalog.resolve_table_reference(reference)?;
233 Ok(())
234}