uqa_sql/schema/table_alteration/
syntax.rs1use crate::{
9 ast::{AlterTableAction, AlterTableStmt, TableLockMode},
10 SQLError,
11};
12
13pub fn table_alter_lock_mode(statement: &AlterTableStmt) -> TableLockMode {
14 let mut mode = TableLockMode::ShareUpdateExclusive;
15 for action in &statement.actions {
16 match action {
17 AlterTableAction::SetTriggerEnableMode { .. }
18 | AlterTableAction::AddForeignKeyConstraint { .. } => {
19 mode = TableLockMode::ShareRowExclusive;
20 }
21 AlterTableAction::ValidateConstraint { .. }
22 | AlterTableAction::AttachPartition { .. }
23 | AlterTableAction::DetachPartition {
24 concurrently: true, ..
25 }
26 | AlterTableAction::DetachPartition { finalize: true, .. } => {}
27 _ => return TableLockMode::AccessExclusive,
28 }
29 }
30 mode
31}
32
33pub fn validate_alter_table_transaction(
34 stmt: &AlterTableStmt,
35 in_transaction_block: bool,
36) -> Result<(), SQLError> {
37 if in_transaction_block
38 && stmt.actions.iter().any(|action| {
39 matches!(
40 action,
41 AlterTableAction::DetachPartition {
42 concurrently: true,
43 ..
44 }
45 )
46 })
47 {
48 return Err(SQLError::Routine {
49 sqlstate: "25001".into(),
50 message: "ALTER TABLE ... DETACH CONCURRENTLY cannot run inside a transaction block"
51 .into(),
52 });
53 }
54 Ok(())
55}
56
57pub fn alter_sequence_from_table_syntax(
58 canonical: &str,
59 stmt: &AlterTableStmt,
60) -> Result<crate::ast::AlterSequence, SQLError> {
61 let mut alter = crate::ast::AlterSequence {
62 name: canonical.to_string(),
63 if_exists: stmt.if_exists,
64 ..crate::ast::AlterSequence::default()
65 };
66 match stmt.actions.as_slice() {
67 [AlterTableAction::SetPersistence { persistence }] => {
68 alter.persistence = Some(*persistence);
69 }
70 [AlterTableAction::RenameTable { to }] => {
71 alter.lifecycle = crate::ast::SequenceLifecycle::RenameTo { name: to.clone() };
72 }
73 [AlterTableAction::SetSchema { schema }] => {
74 alter.lifecycle = crate::ast::SequenceLifecycle::SetSchema {
75 schema: schema.clone(),
76 };
77 }
78 [AlterTableAction::ChangeOwner { owner }] => {
79 alter.role_owner = Some(owner.clone());
80 }
81 _ => {
82 return Err(SQLError::Routine {
83 sqlstate: "42809".into(),
84 message: format!("ALTER TABLE: relation `{canonical}` is a sequence, not a table"),
85 });
86 }
87 }
88 Ok(alter)
89}
90
91pub fn alter_view_from_table_syntax(
93 canonical: &str,
94 kind: &str,
95 stmt: &AlterTableStmt,
96) -> Result<Option<crate::ast::AlterViewStmt>, SQLError> {
97 let action = match stmt.actions.as_slice() {
98 [AlterTableAction::RenameTable { to }] => {
99 Some(crate::ast::AlterViewAction::RenameTo(to.clone()))
100 }
101 [AlterTableAction::ChangeOwner { owner }] => {
102 Some(crate::ast::AlterViewAction::OwnerTo(owner.clone()))
103 }
104 _ => None,
105 };
106 if let Some(action) = action {
107 return Ok(Some(crate::ast::AlterViewStmt {
108 name: canonical.to_string(),
109 kind: if kind == "view" {
110 crate::ast::AlterViewKind::View
111 } else {
112 crate::ast::AlterViewKind::MaterializedView
113 },
114 if_exists: stmt.if_exists,
115 action,
116 }));
117 }
118 if kind == "view"
119 && stmt.actions.iter().all(|action| {
120 matches!(
121 action,
122 AlterTableAction::RenameRule { .. } | AlterTableAction::RenameTrigger { .. }
123 )
124 })
125 {
126 return Ok(None);
127 }
128 Err(SQLError::Routine {
129 sqlstate: "42809".into(),
130 message: format!("ALTER TABLE: relation `{canonical}` is a {kind}, not a table"),
131 })
132}
133
134pub fn alter_foreign_table_from_table_syntax(
136 canonical: &str,
137 stmt: &AlterTableStmt,
138) -> Result<Option<crate::ast::AlterForeignTableStmt>, SQLError> {
139 if stmt.actions.iter().all(|action| {
140 matches!(
141 action,
142 AlterTableAction::RenameTrigger { .. } | AlterTableAction::SetTriggerEnableMode { .. }
143 )
144 }) {
145 return Ok(None);
146 }
147 let action = match stmt.actions.as_slice() {
148 [AlterTableAction::ChangeOwner { owner }] => {
149 crate::ast::AlterForeignTableAction::OwnerTo(owner.clone())
150 }
151 [AlterTableAction::RenameTable { to }] => {
152 crate::ast::AlterForeignTableAction::RenameTo(to.clone())
153 }
154 _ => {
155 return Err(SQLError::Routine {
156 sqlstate: "42809".into(),
157 message: format!(
158 "ALTER TABLE: relation `{canonical}` is a foreign table, not a table"
159 ),
160 });
161 }
162 };
163 Ok(Some(crate::ast::AlterForeignTableStmt {
164 name: canonical.to_string(),
165 if_exists: stmt.if_exists,
166 action,
167 }))
168}
169
170#[cfg(test)]
171mod tests;