use crate::{
ast::{ColumnDef, CreateTable},
type_resolution::FunctionTypeResolver,
ColumnType, SQLError,
};
use std::collections::BTreeSet;
pub fn existing_create_as_target(
name: &str,
if_not_exists: bool,
) -> Result<crate::SQLNotice, SQLError> {
let (_, relation) =
uqa_core::RelationIdentity::parse_reference(name).map_err(SQLError::Unsupported)?;
if if_not_exists {
Ok(
crate::SQLNotice::notice(format!("relation \"{relation}\" already exists, skipping"))
.with_sqlstate("42P07"),
)
} else {
Err(SQLError::Routine {
sqlstate: "42P07".into(),
message: format!("relation \"{relation}\" already exists"),
})
}
}
pub fn validate_create_table_columns(table: &CreateTable) -> Result<(), SQLError> {
validate_relation_column_names_and_types(&table.columns)
}
fn validate_relation_column_names_and_types(columns: &[ColumnDef]) -> Result<(), SQLError> {
for column in columns {
super::columns::validate_postgres_column_name(&column.name)?;
}
for column in columns {
super::columns::validate_postgres_relation_column_type(&column.name, &column.ty)?;
}
Ok(())
}
pub fn validate_create_table_as_columns(
types: &dyn FunctionTypeResolver,
columns: &[ColumnDef],
) -> Result<(), SQLError> {
let mut seen = BTreeSet::new();
for column in columns {
if !seen.insert(&column.name) {
return Err(SQLError::Routine {
sqlstate: "42701".into(),
message: format!("column \"{}\" specified more than once", column.name),
});
}
}
for column in columns {
types.require_type_usage(&column.ty)?;
}
validate_relation_column_names_and_types(columns)
}
pub fn create_table_as_columns(
query_schema: &crate::RowSchema,
column_names: &[String],
) -> Result<Vec<ColumnDef>, SQLError> {
if column_names.len() > query_schema.len() {
return Err(SQLError::Routine {
sqlstate: "42601".into(),
message: "too many column names were specified".into(),
});
}
let names = query_schema
.columns()
.iter()
.enumerate()
.map(|(position, name)| {
column_names
.get(position)
.cloned()
.unwrap_or_else(|| name.clone())
})
.collect::<Vec<_>>();
let columns = names
.into_iter()
.enumerate()
.map(|(position, name)| ColumnDef {
name,
ty: query_schema
.column_type(position)
.cloned()
.unwrap_or(ColumnType::Text),
object_id: None,
attribute_number: None,
missing_value: None,
primary_key: false,
not_null: false,
not_null_explicit: false,
not_null_name: None,
not_null_identity: None,
not_null_validated: true,
not_null_no_inherit: false,
not_null_is_local: true,
auto_increment: None,
unique: false,
default: None,
generated: None,
check: None,
check_name: None,
check_enforced: true,
check_validated: true,
check_no_inherit: false,
check_is_local: true,
check_object_id: None,
check_catalog_oid: None,
default_catalog_oid: None,
references: None,
})
.collect::<Vec<_>>();
Ok(columns)
}
pub mod checks;
pub mod column_declarations;
pub mod declaration;
pub mod foreign_keys;
pub mod keys;
pub mod not_nulls;
#[cfg(test)]
mod tests;