uqa_sql/schema/table_creation/
declaration.rs1use crate::ast::{ColumnDef, CreateTable, Expr, NotNullDeclaration};
9use crate::schema::constraint_metadata::{
10 identity::materialize_default_oid, materialize_check_identity, CatalogIdentityAllocator,
11 ConstraintMetadataError,
12};
13use crate::schema::foreign_keys::ForeignKeyDefinitionContext;
14use crate::schema::indexes::names::{ConstraintIndexNamer, IndexNameCatalog};
15use crate::schema::inheritance::InheritanceContext;
16pub use crate::schema::table_creation::keys::InheritedDefinitions;
17use crate::schema::{SchemaBindingContext, SchemaExpressionCatalog};
18use crate::semantics::conflict::InferenceBindingScope;
19use crate::type_resolution::FunctionTypeResolver;
20use crate::SQLError;
21use std::collections::BTreeSet;
22
23#[cfg(test)]
24mod tests;
25
26pub struct CreateTableAnalysisContext<'a> {
27 pub types: &'a dyn FunctionTypeResolver,
28 pub schema: &'a dyn SchemaExpressionCatalog,
29 pub bindings: &'a dyn InferenceBindingScope,
30 pub inheritance: InheritanceContext<'a>,
31 pub index_names: &'a dyn IndexNameCatalog,
32 pub foreign_keys: ForeignKeyDefinitionContext<'a>,
33}
34
35pub fn declared_row_columns(
37 columns: &mut [ColumnDef],
38 allocate: &mut CatalogIdentityAllocator<'_>,
39) -> Result<Vec<ColumnDef>, SQLError> {
40 crate::catalog::relation_attributes::materialize(columns, &[])?;
41 columns
42 .iter_mut()
43 .map(|column| {
44 if column.object_id.is_none() {
45 column.object_id = Some(
46 allocate
47 .allocate_object_id("column")
48 .map_err(ConstraintMetadataError::into_sql_error)?,
49 );
50 }
51 let mut declared = ColumnDef::nullable(column.name.clone(), column.ty.clone());
52 declared.object_id = column.object_id;
53 declared.attribute_number = column.attribute_number;
54 declared.collation_oid = column.collation_oid;
55 Ok(declared)
56 })
57 .collect()
58}
59
60pub fn transform_create_table(
62 context: &CreateTableAnalysisContext<'_>,
63 c: &mut CreateTable,
64) -> Result<(), SQLError> {
65 use crate::ast::DeclaredElement;
66 let target = super::column_declarations::ColumnDeclarationTarget {
67 table: &c.qualifier,
68 partitioned: c.hierarchy.partition_spec.is_some(),
69 partition: c.hierarchy.partition_bound.is_some(),
70 };
71 let lost =
72 || SQLError::Internal("the written order of CREATE TABLE elements lost a column".into());
73 let mut columns = c.columns.iter_mut();
74 let mut deferrable_key = false;
75 let mut declarations = Vec::new();
76 let mut primary_keys = Vec::new();
77 for element in &c.element_order {
78 match element {
79 DeclaredElement::Column(declaration) => {
80 let column = columns.next().ok_or_else(lost)?;
81 super::column_declarations::check_serial_array(declaration)?;
82 if !c.untyped_columns.contains(&column.name) {
83 column.ty = crate::type_resolution::resolve_declared_column_type(
84 context.types,
85 &column.ty,
86 )?;
87 column.collation_oid = Some(crate::catalog::collations::declarations::select(
88 context.types,
89 &column.ty,
90 declaration.collation.as_deref(),
91 )?);
92 }
93 deferrable_key |= super::column_declarations::check_column_declaration(
94 declaration,
95 &column.name,
96 target,
97 )?;
98 if column.not_null {
100 declarations.push(NotNullDeclaration {
101 column: column.name.clone(),
102 name: column.not_null_name.clone(),
103 no_inherit: column.not_null_no_inherit,
104 explicit: column.not_null_explicit,
105 });
106 }
107 }
108 DeclaredElement::NotNull(declaration) => {
109 if target.partitioned && declaration.no_inherit {
110 return Err(SQLError::Routine {
111 sqlstate: "0A000".into(),
112 message: "not-null constraints on partitioned tables cannot be NO INHERIT"
113 .into(),
114 });
115 }
116 declarations.push(declaration.clone());
117 }
118 DeclaredElement::PrimaryKey { columns } => primary_keys.push(columns.clone()),
119 DeclaredElement::DeferrableKey => deferrable_key = true,
120 }
121 }
122 if columns.next().is_some() {
123 return Err(lost());
124 }
125 if deferrable_key {
126 return Err(SQLError::Unsupported(
127 "CREATE TABLE: DEFERRABLE PRIMARY KEY and UNIQUE constraints are not supported".into(),
128 ));
129 }
130 c.element_order.clear();
131 super::keys::transform_declared_keys(&context.inheritance, c)?;
132 for columns in primary_keys {
134 for column in columns {
135 match declarations
136 .iter()
137 .find(|declaration| declaration.column == column)
138 {
139 Some(declaration) if declaration.no_inherit => {
140 return Err(SQLError::Routine {
141 sqlstate: "42601".into(),
142 message: format!(
143 "conflicting NO INHERIT declaration for not-null constraint on column \"{column}\""
144 ),
145 });
146 }
147 Some(_) => {}
148 None => declarations.push(NotNullDeclaration {
149 column,
150 name: None,
151 no_inherit: false,
152 explicit: false,
153 }),
154 }
155 }
156 }
157 c.not_null_declarations = declarations;
158 Ok(())
159}
160
161pub fn prepare_create_table_declaration(
163 context: &CreateTableAnalysisContext<'_>,
164 c: &mut CreateTable,
165 notices: &mut Vec<crate::SQLNotice>,
166) -> Result<InheritedDefinitions, SQLError> {
167 let declared = c.key_constraints.len();
168 let declared_foreign_keys = c.foreign_keys.len();
169 let parents =
170 super::super::inheritance::merge_create_table_hierarchy(&context.inheritance, c, notices)?;
171 let keys = c.key_constraints.len() - declared;
172 let foreign_keys = c.foreign_keys.len() - declared_foreign_keys;
173 super::keys::declare_primary_key_not_null(&mut c.columns, &c.key_constraints[keys..]);
174 for column in &c.columns {
175 context.types.require_type_usage(&column.ty)?;
176 }
177 super::validate_create_table_columns(c)?;
178 let unique_indexes = match c.hierarchy.parents.first() {
179 Some(parent) if c.hierarchy.is_partition() && c.hierarchy.partition_spec.is_some() => {
180 context
181 .inheritance
182 .catalog
183 .unique_index_keys(parent)
184 .map_err(|error| SQLError::Internal(format!("read parent indexes: {error}")))?
185 }
186 _ => Vec::new(),
187 };
188 Ok(InheritedDefinitions {
189 expressions: parents.expressions,
190 not_nulls: parents.not_nulls,
191 keys,
192 foreign_keys,
193 unique_indexes,
194 })
195}
196
197pub fn define_inherited_expressions(
199 c: &mut CreateTable,
200 inherited: &InheritedDefinitions,
201 allocate: &mut CatalogIdentityAllocator<'_>,
202) -> Result<(), SQLError> {
203 for column in &mut c.columns {
204 if inherited.expressions.contains(&column.name) {
205 allocate_expression_identity(column, allocate)?;
206 }
207 }
208 for check in c.checks.iter_mut().filter(|check| !check.is_local) {
209 materialize_check_identity(&mut check.object_id, &mut check.catalog_oid, allocate)
210 .map_err(ConstraintMetadataError::into_sql_error)?;
211 }
212 Ok(())
213}
214
215fn allocate_expression_identity(
217 column: &mut ColumnDef,
218 allocate: &mut CatalogIdentityAllocator<'_>,
219) -> Result<(), SQLError> {
220 if column.object_id.is_none() {
221 column.object_id = Some(
222 allocate
223 .allocate_object_id("column")
224 .map_err(ConstraintMetadataError::into_sql_error)?,
225 );
226 }
227 materialize_default_oid(column, allocate).map_err(ConstraintMetadataError::into_sql_error)?;
228 Ok(())
229}
230
231pub fn bind_create_table_partitioning(
233 context: &CreateTableAnalysisContext<'_>,
234 c: &mut CreateTable,
235) -> Result<(), SQLError> {
236 super::super::inheritance::bind_create_table_partitioning(&context.inheritance, c)
237}
238
239pub fn define_create_table_defaults(
241 context: &CreateTableAnalysisContext<'_>,
242 c: &mut CreateTable,
243 allocate: &mut CatalogIdentityAllocator<'_>,
244) -> Result<(), SQLError> {
245 let binding = context.bindings.binding_scope()?;
246 let schema = SchemaBindingContext {
247 catalog: context.schema,
248 binding: &binding.context(),
249 };
250 let snapshot = c.columns.clone();
251 for index in 0..c.columns.len() {
252 let column = &mut c.columns[index];
253 if let Some(default) = &mut column.default {
254 if !super::super::defaults::validate_default_expression(
255 &schema,
256 default,
257 &column.ty,
258 &column.name,
259 )? {
260 column.default = None;
261 }
262 }
263 super::super::generated::prepare_generated_column(
264 &schema,
265 &c.qualifier,
266 &snapshot,
267 &mut c.columns,
268 index,
269 &c.foreign_keys,
270 )?;
271 allocate_expression_identity(&mut c.columns[index], allocate)?;
272 }
273 Ok(())
274}
275
276pub fn clone_create_table_parent_keys<'a>(
278 context: &CreateTableAnalysisContext<'a>,
279 c: &mut CreateTable,
280 inherited: &InheritedDefinitions,
281 allocate: &mut CatalogIdentityAllocator<'_>,
282) -> Result<ConstraintIndexNamer<'a>, SQLError> {
283 super::keys::clone_parent_keys(context.index_names, c, inherited, allocate)
284}
285
286pub fn cloned_constraint_names(
288 c: &CreateTable,
289 inherited: &InheritedDefinitions,
290) -> BTreeSet<String> {
291 c.key_constraints[..inherited.keys]
292 .iter()
293 .filter_map(|key| key.name.clone())
294 .chain(
295 c.foreign_keys[..inherited.foreign_keys]
296 .iter()
297 .filter_map(|foreign_key| foreign_key.name.clone()),
298 )
299 .collect()
300}
301
302pub fn define_create_table_constraints(
304 c: &mut CreateTable,
305 indexes: ConstraintIndexNamer<'_>,
306 inherited: &InheritedDefinitions,
307 allocate: &mut CatalogIdentityAllocator<'_>,
308) -> Result<(), SQLError> {
309 super::keys::define_declared_keys(indexes, c, inherited, allocate)
310}
311
312pub(super) fn validate_check_expression(
313 context: &CreateTableAnalysisContext<'_>,
314 table: &str,
315 qualifier: &str,
316 columns: &[ColumnDef],
317 expression: &mut Expr,
318) -> Result<(), SQLError> {
319 let binding = context.bindings.binding_scope()?;
320 super::super::constraints::validate_check_expression(
321 &SchemaBindingContext {
322 catalog: context.schema,
323 binding: &binding.context(),
324 },
325 table,
326 qualifier,
327 columns,
328 expression,
329 )
330}