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