uqa_sql/schema/table_creation/
column_declarations.rs1use crate::ast::{ColumnClause, ColumnClauseKind, ColumnDeclaration};
10use crate::SQLError;
11
12#[derive(Clone, Copy)]
14pub struct ColumnDeclarationTarget<'a> {
15 pub table: &'a str,
17 pub partitioned: bool,
19 pub partition: bool,
21}
22
23pub fn check_serial_array(declaration: &ColumnDeclaration) -> Result<(), SQLError> {
25 if declaration.serial_array {
26 return Err(error("0A000", "array of serial is not implemented".into()));
27 }
28 Ok(())
29}
30
31pub fn check_column_declaration(
33 declaration: &ColumnDeclaration,
34 column: &str,
35 target: ColumnDeclarationTarget<'_>,
36) -> Result<bool, SQLError> {
37 let deferrable_key = check_constraint_attributes(&declaration.clauses)?;
38 ClauseConflicts::new(declaration, column, target, false).check()?;
39 Ok(deferrable_key)
40}
41
42pub fn check_foreign_column_declaration(
44 declaration: &ColumnDeclaration,
45 column: &str,
46 table: &str,
47) -> Result<(), SQLError> {
48 check_constraint_attributes(&declaration.clauses)?;
49 ClauseConflicts::new(
50 declaration,
51 column,
52 ColumnDeclarationTarget {
53 table,
54 partitioned: false,
55 partition: false,
56 },
57 true,
58 )
59 .check()
60}
61
62pub(crate) fn foreign_table_constraint_error(kind: &str) -> SQLError {
63 SQLError::Unsupported(format!(
64 "{kind} constraints are not supported on foreign tables"
65 ))
66}
67
68fn check_constraint_attributes(clauses: &[ColumnClause]) -> Result<bool, SQLError> {
70 use ColumnClauseKind::{
71 Check, Deferrable, Enforced, ForeignKey, InitiallyDeferred, InitiallyImmediate,
72 NotDeferrable, NotEnforced, PrimaryKey, Unique,
73 };
74 let mut last = None;
75 let mut deferrable = false;
76 let mut initially_deferred = false;
77 let mut saw_deferrability = false;
78 let mut saw_initially = false;
79 let mut saw_enforced = false;
80 let mut deferrable_key = false;
81 let syntax = |message: &str| Err(error("42601", message.into()));
82 for clause in clauses {
83 let supports_timing = matches!(last, Some(PrimaryKey | Unique | ForeignKey));
84 match clause.kind {
85 Deferrable | NotDeferrable => {
86 let written = if clause.kind == Deferrable {
87 "DEFERRABLE"
88 } else {
89 "NOT DEFERRABLE"
90 };
91 if !supports_timing {
92 return syntax(&format!("misplaced {written} clause"));
93 }
94 if saw_deferrability {
95 return syntax("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed");
96 }
97 saw_deferrability = true;
98 deferrable = clause.kind == Deferrable;
99 if !deferrable && saw_initially && initially_deferred {
100 return syntax("constraint declared INITIALLY DEFERRED must be DEFERRABLE");
101 }
102 }
103 InitiallyDeferred | InitiallyImmediate => {
104 let written = if clause.kind == InitiallyDeferred {
105 "INITIALLY DEFERRED"
106 } else {
107 "INITIALLY IMMEDIATE"
108 };
109 if !supports_timing {
110 return syntax(&format!("misplaced {written} clause"));
111 }
112 if saw_initially {
113 return syntax("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed");
114 }
115 saw_initially = true;
116 initially_deferred = clause.kind == InitiallyDeferred;
117 if initially_deferred {
118 if !saw_deferrability {
120 deferrable = true;
121 } else if !deferrable {
122 return syntax("constraint declared INITIALLY DEFERRED must be DEFERRABLE");
123 }
124 }
125 }
126 Enforced | NotEnforced => {
127 let written = if clause.kind == Enforced {
128 "ENFORCED"
129 } else {
130 "NOT ENFORCED"
131 };
132 if !matches!(last, Some(Check | ForeignKey)) {
133 return syntax(&format!("misplaced {written} clause"));
134 }
135 if saw_enforced {
136 return syntax("multiple ENFORCED/NOT ENFORCED clauses not allowed");
137 }
138 saw_enforced = true;
139 }
140 kind => {
141 last = Some(kind);
142 deferrable = false;
143 initially_deferred = false;
144 saw_deferrability = false;
145 saw_initially = false;
146 saw_enforced = false;
147 }
148 }
149 deferrable_key |= deferrable && matches!(last, Some(PrimaryKey | Unique));
150 }
151 Ok(deferrable_key)
152}
153
154static SERIAL_DEFAULT: ColumnClause = ColumnClause {
156 kind: ColumnClauseKind::Default,
157 name: None,
158 no_inherit: false,
159};
160
161#[derive(Clone, Copy, PartialEq, Eq)]
163enum Nullability {
164 Unspecified,
165 Null,
166 NotNull,
167}
168
169#[derive(Default)]
171struct SeenClauses {
172 default: bool,
173 identity: bool,
174 generated: bool,
175}
176
177struct SeenNotNull<'a> {
178 name: Option<&'a str>,
179 no_inherit: bool,
180}
181
182struct ClauseConflicts<'a> {
184 declaration: &'a ColumnDeclaration,
185 column: &'a str,
186 target: ColumnDeclarationTarget<'a>,
187 foreign: bool,
188 need_not_null: bool,
189 disallow_no_inherit: bool,
190 nullability: Nullability,
191 not_null: Option<SeenNotNull<'a>>,
192 seen: SeenClauses,
193}
194
195impl<'a> ClauseConflicts<'a> {
196 fn new(
197 declaration: &'a ColumnDeclaration,
198 column: &'a str,
199 target: ColumnDeclarationTarget<'a>,
200 foreign: bool,
201 ) -> Self {
202 let disallow_no_inherit = declaration.serial
204 || declaration.clauses.iter().any(|clause| {
205 matches!(
206 clause.kind,
207 ColumnClauseKind::Identity | ColumnClauseKind::PrimaryKey
208 )
209 });
210 Self {
211 declaration,
212 column,
213 target,
214 foreign,
215 need_not_null: declaration.serial,
216 disallow_no_inherit,
217 nullability: Nullability::Unspecified,
218 not_null: None,
219 seen: SeenClauses::default(),
220 }
221 }
222
223 fn check(mut self) -> Result<(), SQLError> {
224 let serial = self.declaration.serial.then_some(&SERIAL_DEFAULT);
225 let declaration = self.declaration;
226 for clause in declaration.clauses.iter().chain(serial) {
227 self.read(clause)?;
228 self.check_combinations()?;
229 }
230 Ok(())
231 }
232
233 fn read(&mut self, clause: &'a ColumnClause) -> Result<(), SQLError> {
234 match clause.kind {
235 ColumnClauseKind::Null => {
236 if self.nullability == Nullability::NotNull || self.need_not_null {
237 return Err(self.conflicting_nullability());
238 }
239 self.nullability = Nullability::Null;
240 }
241 ColumnClauseKind::NotNull => self.read_not_null(clause)?,
242 ColumnClauseKind::Default => {
243 if self.seen.default {
244 return Err(self.column_error("multiple default values specified"));
245 }
246 self.seen.default = true;
247 }
248 ColumnClauseKind::Identity => {
249 if self.target.partition {
250 return Err(error(
251 "0A000",
252 "identity columns are not supported on partitions".into(),
253 ));
254 }
255 if self.seen.identity {
256 return Err(self.column_error("multiple identity specifications"));
257 }
258 self.seen.identity = true;
259 match self.nullability {
260 Nullability::Unspecified => self.need_not_null = true,
261 Nullability::Null => return Err(self.conflicting_nullability()),
262 Nullability::NotNull => {}
263 }
264 }
265 ColumnClauseKind::Generated => {
266 if self.seen.generated {
267 return Err(self.column_error("multiple generation clauses specified"));
268 }
269 self.seen.generated = true;
270 }
271 ColumnClauseKind::PrimaryKey => {
272 if self.nullability == Nullability::Null {
273 return Err(self.conflicting_nullability());
274 }
275 if self.foreign {
276 return Err(foreign_table_constraint_error("primary key"));
277 }
278 self.need_not_null = true;
279 }
280 ColumnClauseKind::Unique if self.foreign => {
281 return Err(foreign_table_constraint_error("unique"));
282 }
283 ColumnClauseKind::ForeignKey if self.foreign => {
284 return Err(foreign_table_constraint_error("foreign key"));
285 }
286 _ => {}
287 }
288 Ok(())
289 }
290
291 fn read_not_null(&mut self, clause: &'a ColumnClause) -> Result<(), SQLError> {
292 if self.target.partitioned && clause.no_inherit {
293 return Err(error(
294 "0A000",
295 "not-null constraints on partitioned tables cannot be NO INHERIT".into(),
296 ));
297 }
298 if self.nullability == Nullability::Null {
299 return Err(self.conflicting_nullability());
300 }
301 if self.disallow_no_inherit && clause.no_inherit {
302 return Err(self.conflicting_no_inherit());
303 }
304 if self.nullability != Nullability::NotNull {
305 self.nullability = Nullability::NotNull;
306 self.need_not_null = false;
307 self.not_null = Some(SeenNotNull {
308 name: clause.name.as_deref(),
309 no_inherit: clause.no_inherit,
310 });
311 } else if let Some(previous) = &mut self.not_null {
312 if let (Some(previous_name), Some(name)) = (previous.name, clause.name.as_deref()) {
313 if previous_name != name {
314 return Err(error(
315 "XX000",
316 format!(
317 "conflicting not-null constraint names \"{previous_name}\" and \"{name}\""
318 ),
319 ));
320 }
321 }
322 if previous.no_inherit != clause.no_inherit {
323 return Err(self.conflicting_no_inherit());
324 }
325 if previous.name.is_none() {
326 previous.name = clause.name.as_deref();
327 }
328 }
329 Ok(())
330 }
331
332 fn check_combinations(&self) -> Result<(), SQLError> {
333 if self.seen.default && self.seen.identity {
334 return Err(self.column_error("both default and identity specified"));
335 }
336 if self.seen.default && self.seen.generated {
337 return Err(self.column_error("both default and generation expression specified"));
338 }
339 if self.seen.identity && self.seen.generated {
340 return Err(self.column_error("both identity and generation expression specified"));
341 }
342 Ok(())
343 }
344
345 fn column_error(&self, what: &str) -> SQLError {
346 error(
347 "42601",
348 format!(
349 "{what} for column \"{}\" of table \"{}\"",
350 self.column, self.target.table
351 ),
352 )
353 }
354
355 fn conflicting_nullability(&self) -> SQLError {
356 error(
357 "42601",
358 format!(
359 "conflicting NULL/NOT NULL declarations for column \"{}\" of table \"{}\"",
360 self.column, self.target.table
361 ),
362 )
363 }
364
365 fn conflicting_no_inherit(&self) -> SQLError {
366 error(
367 "42601",
368 format!(
369 "conflicting NO INHERIT declarations for not-null constraints on column \"{}\"",
370 self.column
371 ),
372 )
373 }
374}
375
376fn error(sqlstate: &str, message: String) -> SQLError {
377 SQLError::Routine {
378 sqlstate: sqlstate.into(),
379 message,
380 }
381}