uqa_sql/schema/columns/
addition.rs1use crate::{
9 assignment::columns::ColumnCatalogError,
10 ast::{ColumnDef, ForeignKey, TableKeyConstraint},
11 schema::{
12 foreign_keys::ForeignKeyDefinitionContext, SchemaBindingContext, SchemaExpressionCatalog,
13 },
14 semantics::conflict::InferenceBindingScope,
15 SQLError,
16};
17pub trait AddedColumnKeys {
18 fn try_key_constraints(
19 &self,
20 table: &str,
21 ) -> Result<Vec<TableKeyConstraint>, ColumnCatalogError>;
22 fn try_foreign_keys(&self, table: &str) -> Result<Vec<ForeignKey>, ColumnCatalogError>;
23}
24pub struct AddedColumnAnalysisContext<'a> {
25 pub keys: &'a dyn AddedColumnKeys,
26 pub schema: &'a dyn SchemaExpressionCatalog,
27 pub bindings: &'a dyn InferenceBindingScope,
28 pub foreign_keys: ForeignKeyDefinitionContext<'a>,
29}
30fn ddl_storage_error(action: &str, error: ColumnCatalogError) -> SQLError {
31 crate::catalog::errors::storage_error(action, error.as_ref())
32}
33pub fn bind_added_column(
34 context: &AddedColumnAnalysisContext<'_>,
35 table: &str,
36 qualifier: &str,
37 column: &mut ColumnDef,
38) -> Result<(), SQLError> {
39 if let Some(default) = &mut column.default {
40 let binding = context.bindings.binding_scope()?;
41 crate::schema::defaults::validate_default_expression(
42 &SchemaBindingContext {
43 catalog: context.schema,
44 binding: &binding.context(),
45 },
46 default,
47 &column.ty,
48 )?;
49 }
50 let mut candidate_columns = context
51 .foreign_keys
52 .columns
53 .try_describe_table(table)
54 .map_err(|error| ddl_storage_error("ALTER TABLE ADD COLUMN", error))?
55 .ok_or_else(|| SQLError::UnknownTable(table.to_string()))?;
56 candidate_columns.push(column.clone());
57 let check_columns = candidate_columns.clone();
58 if let Some(check) = &mut column.check {
59 let binding = context.bindings.binding_scope()?;
60 crate::schema::constraints::validate_check_expression(
61 &SchemaBindingContext {
62 catalog: context.schema,
63 binding: &binding.context(),
64 },
65 table,
66 qualifier,
67 &check_columns,
68 check,
69 )?;
70 crate::catalog::regrole_dependencies::reject_stored_regrole_constants(
71 context.schema,
72 check,
73 None,
74 )?;
75 candidate_columns
76 .last_mut()
77 .expect("new column candidate exists")
78 .check
79 .clone_from(&column.check);
80 }
81 let key_constraints = context
82 .keys
83 .try_key_constraints(table)
84 .map_err(|error| ddl_storage_error("ALTER TABLE ADD COLUMN", error))?;
85 let foreign_keys = context
86 .keys
87 .try_foreign_keys(table)
88 .map_err(|error| ddl_storage_error("ALTER TABLE ADD COLUMN", error))?;
89 crate::schema::generated::prepare_generated_columns(
90 context.schema,
91 qualifier,
92 &mut candidate_columns,
93 &key_constraints,
94 &foreign_keys,
95 )?;
96 column.generated = candidate_columns
97 .last()
98 .and_then(|candidate| candidate.generated.clone());
99 if let Some(reference) = column.references.clone() {
100 let mut foreign_key = crate::schema::foreign_keys::column_foreign_key(column, &reference);
101 crate::schema::foreign_keys::validate_foreign_key_definition_with_local_state(
102 &context.foreign_keys,
103 table,
104 Some(&candidate_columns),
105 None,
106 &mut foreign_key,
107 )?;
108 let [referenced_column] = foreign_key.ref_columns.as_slice() else {
109 return Err(SQLError::Internal(
110 "column FOREIGN KEY did not resolve exactly one referenced column".into(),
111 ));
112 };
113 let Some(reference) = column.references.as_mut() else {
114 return Err(SQLError::Internal(
115 "column FOREIGN KEY disappeared during validation".into(),
116 ));
117 };
118 reference.table = foreign_key.ref_table;
119 reference.column = Some(referenced_column.clone());
120 }
121 Ok(())
122}