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 if !crate::schema::defaults::validate_default_expression(
42 &SchemaBindingContext {
43 catalog: context.schema,
44 binding: &binding.context(),
45 },
46 default,
47 &column.ty,
48 &column.name,
49 )? {
50 column.default = None;
51 }
52 }
53 let mut candidate_columns = context
54 .foreign_keys
55 .columns
56 .try_describe_table(table)
57 .map_err(|error| ddl_storage_error("ALTER TABLE ADD COLUMN", error))?
58 .ok_or_else(|| SQLError::UnknownTable(table.to_string()))?;
59 candidate_columns.push(column.clone());
60 let check_columns = candidate_columns.clone();
61 if let Some(check) = &mut column.check {
62 let binding = context.bindings.binding_scope()?;
63 crate::schema::constraints::validate_check_expression(
64 &SchemaBindingContext {
65 catalog: context.schema,
66 binding: &binding.context(),
67 },
68 table,
69 qualifier,
70 &check_columns,
71 check,
72 )?;
73 crate::catalog::regrole_dependencies::reject_stored_regrole_constants(
74 context.schema,
75 check,
76 None,
77 )?;
78 candidate_columns
79 .last_mut()
80 .expect("new column candidate exists")
81 .check
82 .clone_from(&column.check);
83 }
84 let foreign_keys = context
85 .keys
86 .try_foreign_keys(table)
87 .map_err(|error| ddl_storage_error("ALTER TABLE ADD COLUMN", error))?;
88 let binding = context.bindings.binding_scope()?;
89 crate::schema::generated::prepare_generated_columns(
90 &SchemaBindingContext {
91 catalog: context.schema,
92 binding: &binding.context(),
93 },
94 qualifier,
95 &mut candidate_columns,
96 &foreign_keys,
97 )?;
98 column.generated = candidate_columns
99 .last()
100 .and_then(|candidate| candidate.generated.clone());
101 if let Some(reference) = column.references.clone() {
102 let mut foreign_key = crate::schema::foreign_keys::column_foreign_key(column, &reference);
103 crate::schema::foreign_keys::validate_foreign_key_definition_with_local_state(
104 &context.foreign_keys,
105 table,
106 Some(&candidate_columns),
107 None,
108 &mut foreign_key,
109 )?;
110 let [referenced_column] = foreign_key.ref_columns.as_slice() else {
111 return Err(SQLError::Internal(
112 "column FOREIGN KEY did not resolve exactly one referenced column".into(),
113 ));
114 };
115 let Some(reference) = column.references.as_mut() else {
116 return Err(SQLError::Internal(
117 "column FOREIGN KEY disappeared during validation".into(),
118 ));
119 };
120 reference.table = foreign_key.ref_table;
121 reference.column = Some(referenced_column.clone());
122 }
123 Ok(())
124}