use super::syntax::{
alter_foreign_table_from_table_syntax, alter_sequence_from_table_syntax,
alter_view_from_table_syntax,
};
use crate::{
ast::{AlterForeignTableStmt, AlterSequence, AlterTableAction, AlterTableStmt, AlterViewStmt},
catalog::resolution::RelationResolution,
schema::relation_alteration::RelationAlterTarget,
SQLError,
};
pub enum BoundTableAlteration {
Table(AlterTableStmt),
Sequence(AlterSequence),
View(AlterViewStmt),
ForeignTable(AlterForeignTableStmt),
IndexRename {
name: String,
new_name: String,
},
ViewEvents {
name: String,
actions: Vec<AlterTableAction>,
},
ForeignTableEvents {
name: String,
actions: Vec<AlterTableAction>,
},
}
pub fn table_alter_target(
resolution: RelationResolution,
statement: &AlterTableStmt,
notice: &mut dyn FnMut(&str),
) -> Result<Option<RelationAlterTarget>, SQLError> {
RelationAlterTarget::resolve(resolution, &statement.table, statement.if_exists, notice)
}
pub fn bind_table_alteration(
target: RelationAlterTarget,
mut statement: AlterTableStmt,
) -> Result<BoundTableAlteration, SQLError> {
let RelationAlterTarget {
canonical, kind, ..
} = target;
let bound = match kind {
"index"
if matches!(
statement.actions.as_slice(),
[AlterTableAction::RenameTable { .. }]
) =>
{
let AlterTableAction::RenameTable { to } = &statement.actions[0] else {
unreachable!();
};
BoundTableAlteration::IndexRename {
name: canonical,
new_name: to.clone(),
}
}
"table" => {
statement.table = canonical;
BoundTableAlteration::Table(statement)
}
"sequence" => BoundTableAlteration::Sequence(alter_sequence_from_table_syntax(
&canonical, &statement,
)?),
"foreign table" => match alter_foreign_table_from_table_syntax(&canonical, &statement)? {
Some(change) => BoundTableAlteration::ForeignTable(change),
None => BoundTableAlteration::ForeignTableEvents {
name: canonical,
actions: statement.actions,
},
},
"view" | "materialized view" => {
match alter_view_from_table_syntax(&canonical, kind, &statement)? {
Some(change) => BoundTableAlteration::View(change),
None => BoundTableAlteration::ViewEvents {
name: canonical,
actions: statement.actions,
},
}
}
_ => {
return Err(SQLError::Routine {
sqlstate: "42809".into(),
message: format!("ALTER TABLE: relation `{canonical}` is a {kind}, not a table"),
});
}
};
Ok(bound)
}
#[cfg(test)]
mod tests;