uqa_sql/schema/
table_creation.rs1use crate::{
9 ast::{ColumnDef, CreateTable},
10 type_resolution::FunctionTypeResolver,
11 ColumnType, SQLError,
12};
13use std::collections::BTreeSet;
14
15pub fn existing_create_as_target(
17 name: &str,
18 if_not_exists: bool,
19) -> Result<crate::SQLNotice, SQLError> {
20 let (_, relation) =
21 uqa_core::RelationIdentity::parse_reference(name).map_err(SQLError::Unsupported)?;
22 if if_not_exists {
23 Ok(
24 crate::SQLNotice::notice(format!("relation \"{relation}\" already exists, skipping"))
25 .with_sqlstate("42P07"),
26 )
27 } else {
28 Err(SQLError::Routine {
29 sqlstate: "42P07".into(),
30 message: format!("relation \"{relation}\" already exists"),
31 })
32 }
33}
34
35pub fn validate_create_table_columns(table: &CreateTable) -> Result<(), SQLError> {
37 validate_relation_column_names_and_types(&table.columns)
38}
39
40fn validate_relation_column_names_and_types(columns: &[ColumnDef]) -> Result<(), SQLError> {
41 for column in columns {
42 super::columns::validate_postgres_column_name(&column.name)?;
43 }
44 for column in columns {
45 super::columns::validate_postgres_relation_column_type(&column.name, &column.ty)?;
46 }
47 Ok(())
48}
49
50pub fn validate_create_table_as_columns(
52 types: &dyn FunctionTypeResolver,
53 columns: &[ColumnDef],
54) -> Result<(), SQLError> {
55 let mut seen = BTreeSet::new();
56 for column in columns {
57 if !seen.insert(&column.name) {
58 return Err(SQLError::Routine {
59 sqlstate: "42701".into(),
60 message: format!("column \"{}\" specified more than once", column.name),
61 });
62 }
63 }
64 for column in columns {
65 types.require_type_usage(&column.ty)?;
66 }
67 validate_relation_column_names_and_types(columns)
68}
69
70pub fn create_table_as_columns(
72 query_schema: &crate::RowSchema,
73 column_names: &[String],
74) -> Result<Vec<ColumnDef>, SQLError> {
75 if column_names.len() > query_schema.len() {
76 return Err(SQLError::Routine {
77 sqlstate: "42601".into(),
78 message: "too many column names were specified".into(),
79 });
80 }
81 let names = query_schema
82 .columns()
83 .iter()
84 .enumerate()
85 .map(|(position, name)| {
86 column_names
87 .get(position)
88 .cloned()
89 .unwrap_or_else(|| name.clone())
90 })
91 .collect::<Vec<_>>();
92 let columns = names
93 .into_iter()
94 .enumerate()
95 .map(|(position, name)| ColumnDef {
96 name,
97 ty: query_schema
98 .column_type(position)
99 .cloned()
100 .unwrap_or(ColumnType::Text),
101 object_id: None,
102 attribute_number: None,
103 missing_value: None,
104 primary_key: false,
105 not_null: false,
106 not_null_explicit: false,
107 not_null_name: None,
108 not_null_identity: None,
109 not_null_validated: true,
110 not_null_no_inherit: false,
111 not_null_is_local: true,
112 auto_increment: None,
113 unique: false,
114 default: None,
115 generated: None,
116 check: None,
117 check_name: None,
118 check_enforced: true,
119 check_validated: true,
120 check_no_inherit: false,
121 check_is_local: true,
122 check_object_id: None,
123 check_catalog_oid: None,
124 default_catalog_oid: None,
125 references: None,
126 })
127 .collect::<Vec<_>>();
128 Ok(columns)
129}
130
131pub mod checks;
132pub mod column_declarations;
133pub mod declaration;
134pub mod foreign_keys;
135pub mod keys;
136pub mod not_nulls;
137
138#[cfg(test)]
139mod tests;