1#[cfg(not(feature = "std"))]
17use alloc::{boxed::Box, string::ToString, vec::Vec};
18use core::fmt;
19
20#[cfg(feature = "serde")]
21use serde::{Deserialize, Serialize};
22
23use crate::ast::{display_comma_separated, display_separated, DataType, Expr, Ident, ObjectName};
24use crate::tokenizer::Token;
25
26#[derive(Debug, Clone, PartialEq, Eq, Hash)]
28#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29pub enum AlterTableOperation {
30 AddConstraint(TableConstraint),
32 AddColumn { column_def: ColumnDef },
34 DropConstraint {
36 name: Ident,
37 cascade: bool,
38 restrict: bool,
39 },
40 DropColumn {
42 column_name: Ident,
43 if_exists: bool,
44 cascade: bool,
45 },
46 RenamePartitions {
48 old_partitions: Vec<Expr>,
49 new_partitions: Vec<Expr>,
50 },
51 AddPartitions {
53 if_not_exists: bool,
54 new_partitions: Vec<Expr>,
55 },
56 DropPartitions {
57 partitions: Vec<Expr>,
58 if_exists: bool,
59 },
60 RenameColumn {
62 old_column_name: Ident,
63 new_column_name: Ident,
64 },
65 RenameTable { table_name: ObjectName },
67}
68
69impl fmt::Display for AlterTableOperation {
70 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71 match self {
72 AlterTableOperation::AddPartitions {
73 if_not_exists,
74 new_partitions,
75 } => write!(
76 f,
77 "ADD{ine} PARTITION ({})",
78 display_comma_separated(new_partitions),
79 ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
80 ),
81 AlterTableOperation::AddConstraint(c) => write!(f, "ADD {}", c),
82 AlterTableOperation::AddColumn { column_def } => {
83 write!(f, "ADD COLUMN {}", column_def.to_string())
84 }
85 AlterTableOperation::DropPartitions {
86 partitions,
87 if_exists,
88 } => write!(
89 f,
90 "DROP{ie} PARTITION ({})",
91 display_comma_separated(partitions),
92 ie = if *if_exists { " IF EXISTS" } else { "" }
93 ),
94 AlterTableOperation::DropConstraint {
95 name,
96 cascade,
97 restrict,
98 } => {
99 if *cascade {
100 write!(f, "DROP CONSTRAINT {} CASCADE", name)
101 } else if *restrict {
102 write!(f, "DROP CONSTRAINT {} RESTRICT", name)
103 } else {
104 write!(f, "DROP CONSTRAINT {}", name)
105 }
106 }
107 AlterTableOperation::DropColumn {
108 column_name,
109 if_exists,
110 cascade,
111 } => write!(
112 f,
113 "DROP COLUMN {}{}{}",
114 if *if_exists { "IF EXISTS " } else { "" },
115 column_name,
116 if *cascade { " CASCADE" } else { "" }
117 ),
118 AlterTableOperation::RenamePartitions {
119 old_partitions,
120 new_partitions,
121 } => write!(
122 f,
123 "PARTITION ({}) RENAME TO PARTITION ({})",
124 display_comma_separated(old_partitions),
125 display_comma_separated(new_partitions)
126 ),
127 AlterTableOperation::RenameColumn {
128 old_column_name,
129 new_column_name,
130 } => write!(
131 f,
132 "RENAME COLUMN {} TO {}",
133 old_column_name, new_column_name
134 ),
135 AlterTableOperation::RenameTable { table_name } => {
136 write!(f, "RENAME TO {}", table_name)
137 }
138 }
139 }
140}
141
142#[derive(Debug, Clone, PartialEq, Eq, Hash)]
145#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
146pub enum TableConstraint {
147 Unique(Unique),
149 ForeignKey(ForeignKey),
155 Check(Check),
157}
158#[derive(Debug, Clone, PartialEq, Eq, Hash)]
160pub struct Unique {
161 pub name: Option<Ident>,
162 pub columns: Vec<Ident>,
163 pub is_primary: bool,
165}
166#[derive(Debug, Clone, PartialEq, Eq, Hash)]
168pub struct Check {
169 pub name: Option<Ident>,
170 pub expr: Box<Expr>,
171}
172
173#[derive(Debug, Clone, PartialEq, Eq, Hash)]
179pub struct ForeignKey {
180 pub name: Option<Ident>,
181 pub columns: Vec<Ident>,
182 pub foreign_table: ObjectName,
183 pub referred_columns: Vec<Ident>,
184 pub on_delete: Option<ReferentialAction>,
185 pub on_update: Option<ReferentialAction>,
186}
187
188impl fmt::Display for TableConstraint {
189 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
190 match self {
191 TableConstraint::Unique(Unique {
192 name,
193 columns,
194 is_primary,
195 }) => write!(
196 f,
197 "{}{} ({})",
198 display_constraint_name(name),
199 if *is_primary { "PRIMARY KEY" } else { "UNIQUE" },
200 display_comma_separated(columns)
201 ),
202 TableConstraint::ForeignKey(ForeignKey {
203 name,
204 columns,
205 foreign_table,
206 referred_columns,
207 on_delete,
208 on_update,
209 }) => {
210 write!(
211 f,
212 "{}FOREIGN KEY ({}) REFERENCES {}({})",
213 display_constraint_name(name),
214 display_comma_separated(columns),
215 foreign_table,
216 display_comma_separated(referred_columns),
217 )?;
218 if let Some(action) = on_delete {
219 write!(f, " ON DELETE {}", action)?;
220 }
221 if let Some(action) = on_update {
222 write!(f, " ON UPDATE {}", action)?;
223 }
224 Ok(())
225 }
226 TableConstraint::Check(Check { name, expr }) => {
227 write!(f, "{}CHECK ({})", display_constraint_name(name), expr)
228 }
229 }
230 }
231}
232
233#[derive(Debug, Clone, PartialEq, Eq, Hash)]
235#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
236pub struct ColumnDef {
237 pub name: Ident,
238 pub data_type: DataType,
239 pub collation: Option<ObjectName>,
240 pub options: Vec<ColumnOptionDef>,
241}
242
243impl fmt::Display for ColumnDef {
244 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
245 write!(f, "{} {}", self.name, self.data_type)?;
246 for option in &self.options {
247 write!(f, " {}", option)?;
248 }
249 Ok(())
250 }
251}
252
253#[derive(Debug, Clone, PartialEq, Eq, Hash)]
270#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
271pub struct ColumnOptionDef {
272 pub name: Option<Ident>,
273 pub option: ColumnOption,
274}
275
276impl fmt::Display for ColumnOptionDef {
277 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
278 write!(f, "{}{}", display_constraint_name(&self.name), self.option)
279 }
280}
281
282#[derive(Debug, Clone, PartialEq, Eq, Hash)]
285#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
286pub enum ColumnOption {
287 Null,
289 NotNull,
291 Default(Expr),
293 Unique { is_primary: bool },
295 ForeignKey {
301 foreign_table: ObjectName,
302 referred_columns: Vec<Ident>,
303 on_delete: Option<ReferentialAction>,
304 on_update: Option<ReferentialAction>,
305 },
306 Check(Expr),
308 DialectSpecific(Vec<Token>),
312}
313
314impl fmt::Display for ColumnOption {
315 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
316 use ColumnOption::*;
317 match self {
318 Null => write!(f, "NULL"),
319 NotNull => write!(f, "NOT NULL"),
320 Default(expr) => write!(f, "DEFAULT {}", expr),
321 Unique { is_primary } => {
322 write!(f, "{}", if *is_primary { "PRIMARY KEY" } else { "UNIQUE" })
323 }
324 ForeignKey {
325 foreign_table,
326 referred_columns,
327 on_delete,
328 on_update,
329 } => {
330 write!(f, "REFERENCES {}", foreign_table)?;
331 if !referred_columns.is_empty() {
332 write!(f, " ({})", display_comma_separated(referred_columns))?;
333 }
334 if let Some(action) = on_delete {
335 write!(f, " ON DELETE {}", action)?;
336 }
337 if let Some(action) = on_update {
338 write!(f, " ON UPDATE {}", action)?;
339 }
340 Ok(())
341 }
342 Check(expr) => write!(f, "CHECK ({})", expr),
343 DialectSpecific(val) => write!(f, "{}", display_separated(val, " ")),
344 }
345 }
346}
347
348fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
349 struct ConstraintName<'a>(&'a Option<Ident>);
350 impl<'a> fmt::Display for ConstraintName<'a> {
351 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
352 if let Some(name) = self.0 {
353 write!(f, "CONSTRAINT {} ", name)?;
354 }
355 Ok(())
356 }
357 }
358 ConstraintName(name)
359}
360
361#[derive(Debug, Clone, PartialEq, Eq, Hash)]
366#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
367pub enum ReferentialAction {
368 Restrict,
369 Cascade,
370 SetNull,
371 NoAction,
372 SetDefault,
373}
374
375impl fmt::Display for ReferentialAction {
376 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
377 f.write_str(match self {
378 ReferentialAction::Restrict => "RESTRICT",
379 ReferentialAction::Cascade => "CASCADE",
380 ReferentialAction::SetNull => "SET NULL",
381 ReferentialAction::NoAction => "NO ACTION",
382 ReferentialAction::SetDefault => "SET DEFAULT",
383 })
384 }
385}