1use crate::{
9 ast::{ColumnDef, ColumnType, ForeignKey, TableCheck, TableKeyConstraint},
10 SQLError,
11};
12pub fn validate_added_key_columns(
13 table: &str,
14 constraint: &TableKeyConstraint,
15 columns: &[ColumnDef],
16) -> Result<(), SQLError> {
17 let column_names: std::collections::BTreeSet<&str> =
18 columns.iter().map(|column| column.name.as_str()).collect();
19 for column in &constraint.columns {
20 if !column_names.contains(column.as_str()) {
21 return Err(SQLError::TypeMismatch(format!(
22 "ALTER TABLE ADD CONSTRAINT references unknown column `{column}`"
23 )));
24 }
25 }
26 if constraint.without_overlaps {
27 let period_column = constraint.columns.last().ok_or_else(|| {
28 SQLError::TypeMismatch(
29 "constraint using WITHOUT OVERLAPS needs at least two columns".into(),
30 )
31 })?;
32 let period_type = columns
33 .iter()
34 .find(|column| column.name == *period_column)
35 .map(|column| &column.ty)
36 .ok_or_else(|| SQLError::UnknownColumn(format!("{table}.{period_column}")))?;
37 if !matches!(
38 period_type,
39 ColumnType::Range(_) | ColumnType::Multirange(_)
40 ) {
41 return Err(SQLError::Routine {
42 sqlstate: "42804".into(),
43 message: format!(
44 "column \"{period_column}\" in WITHOUT OVERLAPS is not a range or multirange type"
45 ),
46 });
47 }
48 if constraint.columns.len() < 2 {
49 return Err(SQLError::TypeMismatch(
50 "constraint using WITHOUT OVERLAPS needs at least two columns".into(),
51 ));
52 }
53 }
54
55 Ok(())
56}
57pub fn validate_added_key_identity(
58 table: &str,
59 constraint: &TableKeyConstraint,
60 existing_keys: &[TableKeyConstraint],
61 checks: &[TableCheck],
62 foreign_keys: &[ForeignKey],
63) -> Result<(), SQLError> {
64 if let Some(name) = constraint.name.as_deref() {
65 let check_name_exists = checks
66 .iter()
67 .any(|existing| existing.name.as_deref() == Some(name));
68 let foreign_name_exists = foreign_keys
69 .iter()
70 .any(|existing| existing.name.as_deref() == Some(name));
71 let key_name_exists = existing_keys
72 .iter()
73 .any(|existing| existing.name.as_deref() == Some(name));
74 if check_name_exists || foreign_name_exists || key_name_exists {
75 return Err(SQLError::TypeMismatch(format!(
76 "constraint `{name}` already exists on table `{table}`"
77 )));
78 }
79 }
80 if constraint.kind == crate::ast::TableKeyConstraintKind::PrimaryKey
81 && existing_keys
82 .iter()
83 .any(|existing| existing.kind == crate::ast::TableKeyConstraintKind::PrimaryKey)
84 {
85 return Err(SQLError::TypeMismatch(format!(
86 "multiple PRIMARY KEY constraints are not allowed on table `{table}`"
87 )));
88 }
89
90 Ok(())
91}
92
93pub fn apply_primary_key_columns(
95 table: &str,
96 constraint: &TableKeyConstraint,
97 columns: &mut [ColumnDef],
98) -> Result<(), String> {
99 if constraint.kind == crate::ast::TableKeyConstraintKind::PrimaryKey {
100 for key_column in &constraint.columns {
101 let column = columns
102 .iter_mut()
103 .find(|column| column.name == *key_column)
104 .ok_or_else(|| {
105 format!("column `{key_column}` does not exist on table `{table}`")
106 })?;
107 column.not_null = true;
108 }
109 }
110 Ok(())
111}