uqa_sql/schema/
columns.rs1use crate::{ColumnType, SQLError};
10
11pub const POSTGRES_SYSTEM_COLUMNS: [&str; 6] = ["tableoid", "xmin", "cmin", "xmax", "cmax", "ctid"];
12
13pub fn validate_postgres_column_name(name: &str) -> Result<(), SQLError> {
14 if POSTGRES_SYSTEM_COLUMNS.contains(&name) {
15 return Err(SQLError::Routine {
16 sqlstate: "42701".into(),
17 message: format!("column name \"{name}\" conflicts with a system column name"),
18 });
19 }
20 Ok(())
21}
22
23pub fn validate_postgres_relation_column_type(name: &str, ty: &ColumnType) -> Result<(), SQLError> {
24 let pseudo_type = match ty {
25 ColumnType::Void | ColumnType::AnyArray | ColumnType::Record => Some(ty.sql_name()),
26 ColumnType::Array(element)
27 if matches!(
28 element.as_ref(),
29 ColumnType::Void | ColumnType::AnyArray | ColumnType::Record
30 ) =>
31 {
32 Some(ty.sql_name())
33 }
34 _ => None,
35 };
36 if let Some(pseudo_type) = pseudo_type {
37 return Err(SQLError::Routine {
38 sqlstate: "42P16".into(),
39 message: format!("column \"{name}\" has pseudo-type {pseudo_type}"),
40 });
41 }
42 Ok(())
43}
44
45pub fn append_registered_column(
47 table: &str,
48 columns: &mut Vec<crate::ast::ColumnDef>,
49 column: crate::ast::ColumnDef,
50) -> Result<(), String> {
51 if columns.iter().any(|existing| existing.name == column.name) {
52 return Err(format!(
53 "column `{}` already exists on table `{table}`",
54 column.name
55 ));
56 }
57 columns.push(column);
58 Ok(())
59}
60
61pub fn reject_default_change(
63 catalog: &dyn crate::assignment::columns::AssignmentColumnCatalog,
64 table: &str,
65 column: &str,
66 setting: bool,
67) -> Result<(), SQLError> {
68 let Some(shape) = catalog
69 .try_column_shape(table, column)
70 .map_err(|error| SQLError::Internal(format!("read column `{column}`: {error}")))?
71 .flatten()
72 else {
73 return Ok(());
74 };
75 let relation = uqa_core::RelationIdentity::from_legacy_name(table)
76 .map_err(|error| SQLError::Internal(format!("resolve ALTER TABLE target: {error}")))?
77 .name;
78 let (kind, hint) = if shape.identity_sequence.is_some() {
79 (
80 "an identity column",
81 (!setting).then_some("ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY"),
82 )
83 } else if let Some(generated) = shape.generated {
84 (
85 "a generated column",
86 if setting {
87 Some("ALTER TABLE ... ALTER COLUMN ... SET EXPRESSION")
88 } else {
89 (generated == crate::ast::GeneratedColumnKind::Stored)
90 .then_some("ALTER TABLE ... ALTER COLUMN ... DROP EXPRESSION")
91 },
92 )
93 } else {
94 return Ok(());
95 };
96 Err(SQLError::Diagnostic {
97 sqlstate: "42601".into(),
98 message: format!("column \"{column}\" of relation \"{relation}\" is {kind}"),
99 detail: None,
100 hint: hint.map(|command| format!("Use {command} instead.")),
101 })
102}
103
104pub mod addition;
105
106pub mod publication;
107
108pub mod alteration;
109
110pub mod removal;
111
112pub mod removal_metadata;