1#[cfg(not(feature = "std"))]
17use alloc::{boxed::Box, string::String, vec::Vec};
18use core::fmt;
19
20#[cfg(feature = "serde")]
21use serde::{Deserialize, Serialize};
22
23#[cfg(feature = "visitor")]
24use sqlparser_derive::{Visit, VisitMut};
25
26use crate::ast::value::escape_single_quote_string;
27use crate::ast::{
28 display_comma_separated, display_separated, DataType, Expr, Ident, ObjectName, SequenceOptions,
29};
30use crate::tokenizer::Token;
31
32#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
34#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
35#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
36pub enum AlterTableOperation {
37 AddConstraint(TableConstraint),
39 AddColumn {
41 column_keyword: bool,
43 if_not_exists: bool,
45 column_def: ColumnDef,
47 },
48 DropConstraint {
50 if_exists: bool,
51 name: Ident,
52 cascade: bool,
53 },
54 DropColumn {
56 column_name: Ident,
57 if_exists: bool,
58 cascade: bool,
59 },
60 DropPrimaryKey,
64 RenamePartitions {
66 old_partitions: Vec<Expr>,
67 new_partitions: Vec<Expr>,
68 },
69 AddPartitions {
71 if_not_exists: bool,
72 new_partitions: Vec<Expr>,
73 },
74 DropPartitions {
75 partitions: Vec<Expr>,
76 if_exists: bool,
77 },
78 RenameColumn {
80 old_column_name: Ident,
81 new_column_name: Ident,
82 },
83 RenameTable { table_name: ObjectName },
85 ChangeColumn {
87 old_name: Ident,
88 new_name: Ident,
89 data_type: DataType,
90 options: Vec<ColumnOption>,
91 },
92 RenameConstraint { old_name: Ident, new_name: Ident },
96 AlterColumn {
98 column_name: Ident,
99 op: AlterColumnOperation,
100 },
101 SwapWith { table_name: ObjectName },
105}
106
107#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
108#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
109#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
110pub enum AlterIndexOperation {
111 RenameIndex { index_name: ObjectName },
112}
113
114impl fmt::Display for AlterTableOperation {
115 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116 match self {
117 AlterTableOperation::AddPartitions {
118 if_not_exists,
119 new_partitions,
120 } => write!(
121 f,
122 "ADD{ine} PARTITION ({})",
123 display_comma_separated(new_partitions),
124 ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
125 ),
126 AlterTableOperation::AddConstraint(c) => write!(f, "ADD {c}"),
127 AlterTableOperation::AddColumn {
128 column_keyword,
129 if_not_exists,
130 column_def,
131 } => {
132 write!(f, "ADD")?;
133 if *column_keyword {
134 write!(f, " COLUMN")?;
135 }
136 if *if_not_exists {
137 write!(f, " IF NOT EXISTS")?;
138 }
139 write!(f, " {column_def}")?;
140
141 Ok(())
142 }
143 AlterTableOperation::AlterColumn { column_name, op } => {
144 write!(f, "ALTER COLUMN {column_name} {op}")
145 }
146 AlterTableOperation::DropPartitions {
147 partitions,
148 if_exists,
149 } => write!(
150 f,
151 "DROP{ie} PARTITION ({})",
152 display_comma_separated(partitions),
153 ie = if *if_exists { " IF EXISTS" } else { "" }
154 ),
155 AlterTableOperation::DropConstraint {
156 if_exists,
157 name,
158 cascade,
159 } => {
160 write!(
161 f,
162 "DROP CONSTRAINT {}{}{}",
163 if *if_exists { "IF EXISTS " } else { "" },
164 name,
165 if *cascade { " CASCADE" } else { "" },
166 )
167 }
168 AlterTableOperation::DropPrimaryKey => write!(f, "DROP PRIMARY KEY"),
169 AlterTableOperation::DropColumn {
170 column_name,
171 if_exists,
172 cascade,
173 } => write!(
174 f,
175 "DROP COLUMN {}{}{}",
176 if *if_exists { "IF EXISTS " } else { "" },
177 column_name,
178 if *cascade { " CASCADE" } else { "" }
179 ),
180 AlterTableOperation::RenamePartitions {
181 old_partitions,
182 new_partitions,
183 } => write!(
184 f,
185 "PARTITION ({}) RENAME TO PARTITION ({})",
186 display_comma_separated(old_partitions),
187 display_comma_separated(new_partitions)
188 ),
189 AlterTableOperation::RenameColumn {
190 old_column_name,
191 new_column_name,
192 } => write!(f, "RENAME COLUMN {old_column_name} TO {new_column_name}"),
193 AlterTableOperation::RenameTable { table_name } => {
194 write!(f, "RENAME TO {table_name}")
195 }
196 AlterTableOperation::ChangeColumn {
197 old_name,
198 new_name,
199 data_type,
200 options,
201 } => {
202 write!(f, "CHANGE COLUMN {old_name} {new_name} {data_type}")?;
203 if options.is_empty() {
204 Ok(())
205 } else {
206 write!(f, " {}", display_separated(options, " "))
207 }
208 }
209 AlterTableOperation::RenameConstraint { old_name, new_name } => {
210 write!(f, "RENAME CONSTRAINT {old_name} TO {new_name}")
211 }
212 AlterTableOperation::SwapWith { table_name } => {
213 write!(f, "SWAP WITH {table_name}")
214 }
215 }
216 }
217}
218
219impl fmt::Display for AlterIndexOperation {
220 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221 match self {
222 AlterIndexOperation::RenameIndex { index_name } => {
223 write!(f, "RENAME TO {index_name}")
224 }
225 }
226 }
227}
228
229#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
231#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
232#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
233pub enum AlterColumnOperation {
234 SetNotNull,
236 DropNotNull,
238 SetDefault { value: Expr },
240 DropDefault,
242 SetDataType {
244 data_type: DataType,
245 using: Option<Expr>,
247 },
248}
249
250impl fmt::Display for AlterColumnOperation {
251 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
252 match self {
253 AlterColumnOperation::SetNotNull => write!(f, "SET NOT NULL",),
254 AlterColumnOperation::DropNotNull => write!(f, "DROP NOT NULL",),
255 AlterColumnOperation::SetDefault { value } => {
256 write!(f, "SET DEFAULT {value}")
257 }
258 AlterColumnOperation::DropDefault {} => {
259 write!(f, "DROP DEFAULT")
260 }
261 AlterColumnOperation::SetDataType { data_type, using } => {
262 if let Some(expr) = using {
263 write!(f, "SET DATA TYPE {data_type} USING {expr}")
264 } else {
265 write!(f, "SET DATA TYPE {data_type}")
266 }
267 }
268 }
269 }
270}
271
272#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
275#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
276#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
277pub enum TableConstraint {
278 Unique {
280 name: Option<Ident>,
281 columns: Vec<Ident>,
282 is_primary: bool,
284 },
285 ForeignKey {
291 name: Option<Ident>,
292 columns: Vec<Ident>,
293 foreign_table: ObjectName,
294 referred_columns: Vec<Ident>,
295 on_delete: Option<ReferentialAction>,
296 on_update: Option<ReferentialAction>,
297 },
298 Check {
300 name: Option<Ident>,
301 expr: Box<Expr>,
302 },
303 Index {
310 display_as_key: bool,
312 name: Option<Ident>,
314 index_type: Option<IndexType>,
318 columns: Vec<Ident>,
320 },
321 FulltextOrSpatial {
335 fulltext: bool,
337 index_type_display: KeyOrIndexDisplay,
339 opt_index_name: Option<Ident>,
341 columns: Vec<Ident>,
343 },
344}
345
346impl fmt::Display for TableConstraint {
347 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
348 match self {
349 TableConstraint::Unique {
350 name,
351 columns,
352 is_primary,
353 } => write!(
354 f,
355 "{}{} ({})",
356 display_constraint_name(name),
357 if *is_primary { "PRIMARY KEY" } else { "UNIQUE" },
358 display_comma_separated(columns)
359 ),
360 TableConstraint::ForeignKey {
361 name,
362 columns,
363 foreign_table,
364 referred_columns,
365 on_delete,
366 on_update,
367 } => {
368 write!(
369 f,
370 "{}FOREIGN KEY ({}) REFERENCES {}({})",
371 display_constraint_name(name),
372 display_comma_separated(columns),
373 foreign_table,
374 display_comma_separated(referred_columns),
375 )?;
376 if let Some(action) = on_delete {
377 write!(f, " ON DELETE {action}")?;
378 }
379 if let Some(action) = on_update {
380 write!(f, " ON UPDATE {action}")?;
381 }
382 Ok(())
383 }
384 TableConstraint::Check { name, expr } => {
385 write!(f, "{}CHECK ({})", display_constraint_name(name), expr)
386 }
387 TableConstraint::Index {
388 display_as_key,
389 name,
390 index_type,
391 columns,
392 } => {
393 write!(f, "{}", if *display_as_key { "KEY" } else { "INDEX" })?;
394 if let Some(name) = name {
395 write!(f, " {name}")?;
396 }
397 if let Some(index_type) = index_type {
398 write!(f, " USING {index_type}")?;
399 }
400 write!(f, " ({})", display_comma_separated(columns))?;
401
402 Ok(())
403 }
404 Self::FulltextOrSpatial {
405 fulltext,
406 index_type_display,
407 opt_index_name,
408 columns,
409 } => {
410 if *fulltext {
411 write!(f, "FULLTEXT")?;
412 } else {
413 write!(f, "SPATIAL")?;
414 }
415
416 if !matches!(index_type_display, KeyOrIndexDisplay::None) {
417 write!(f, " {index_type_display}")?;
418 }
419
420 if let Some(name) = opt_index_name {
421 write!(f, " {name}")?;
422 }
423
424 write!(f, " ({})", display_comma_separated(columns))?;
425
426 Ok(())
427 }
428 }
429 }
430}
431
432#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
440#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
441#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
442pub enum KeyOrIndexDisplay {
443 None,
445 Key,
447 Index,
449}
450
451impl fmt::Display for KeyOrIndexDisplay {
452 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
453 match self {
454 KeyOrIndexDisplay::None => {
455 write!(f, "")
456 }
457 KeyOrIndexDisplay::Key => {
458 write!(f, "KEY")
459 }
460 KeyOrIndexDisplay::Index => {
461 write!(f, "INDEX")
462 }
463 }
464 }
465}
466
467#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
476#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
477#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
478pub enum IndexType {
479 BTree,
480 Hash,
481 }
483
484impl fmt::Display for IndexType {
485 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
486 match self {
487 Self::BTree => write!(f, "BTREE"),
488 Self::Hash => write!(f, "HASH"),
489 }
490 }
491}
492
493#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
495#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
496#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
497pub struct ColumnDef {
498 pub name: Ident,
499 pub data_type: DataType,
500 pub collation: Option<ObjectName>,
501 pub options: Vec<ColumnOptionDef>,
502}
503
504impl fmt::Display for ColumnDef {
505 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
506 write!(f, "{} {}", self.name, self.data_type)?;
507 for option in &self.options {
508 write!(f, " {option}")?;
509 }
510 Ok(())
511 }
512}
513
514#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
531#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
532#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
533pub struct ColumnOptionDef {
534 pub name: Option<Ident>,
535 pub option: ColumnOption,
536}
537
538impl fmt::Display for ColumnOptionDef {
539 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
540 write!(f, "{}{}", display_constraint_name(&self.name), self.option)
541 }
542}
543
544#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
547#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
548#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
549pub enum ColumnOption {
550 Null,
552 NotNull,
554 Default(Expr),
556 Unique {
558 is_primary: bool,
559 },
560 ForeignKey {
566 foreign_table: ObjectName,
567 referred_columns: Vec<Ident>,
568 on_delete: Option<ReferentialAction>,
569 on_update: Option<ReferentialAction>,
570 },
571 Check(Expr),
573 DialectSpecific(Vec<Token>),
577 CharacterSet(ObjectName),
578 Comment(String),
579 OnUpdate(Expr),
580 Generated {
583 generated_as: GeneratedAs,
584 sequence_options: Option<Vec<SequenceOptions>>,
585 generation_expr: Option<Expr>,
586 },
587}
588
589impl fmt::Display for ColumnOption {
590 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
591 use ColumnOption::*;
592 match self {
593 Null => write!(f, "NULL"),
594 NotNull => write!(f, "NOT NULL"),
595 Default(expr) => write!(f, "DEFAULT {expr}"),
596 Unique { is_primary } => {
597 write!(f, "{}", if *is_primary { "PRIMARY KEY" } else { "UNIQUE" })
598 }
599 ForeignKey {
600 foreign_table,
601 referred_columns,
602 on_delete,
603 on_update,
604 } => {
605 write!(f, "REFERENCES {foreign_table}")?;
606 if !referred_columns.is_empty() {
607 write!(f, " ({})", display_comma_separated(referred_columns))?;
608 }
609 if let Some(action) = on_delete {
610 write!(f, " ON DELETE {action}")?;
611 }
612 if let Some(action) = on_update {
613 write!(f, " ON UPDATE {action}")?;
614 }
615 Ok(())
616 }
617 Check(expr) => write!(f, "CHECK ({expr})"),
618 DialectSpecific(val) => write!(f, "{}", display_separated(val, " ")),
619 CharacterSet(n) => write!(f, "CHARACTER SET {n}"),
620 Comment(v) => write!(f, "COMMENT '{}'", escape_single_quote_string(v)),
621 OnUpdate(expr) => write!(f, "ON UPDATE {expr}"),
622 Generated {
623 generated_as,
624 sequence_options,
625 generation_expr,
626 } => match generated_as {
627 GeneratedAs::Always => {
628 write!(f, "GENERATED ALWAYS AS IDENTITY")?;
629 if sequence_options.is_some() {
630 let so = sequence_options.as_ref().unwrap();
631 if !so.is_empty() {
632 write!(f, " (")?;
633 }
634 for sequence_option in so {
635 write!(f, "{sequence_option}")?;
636 }
637 if !so.is_empty() {
638 write!(f, " )")?;
639 }
640 }
641 Ok(())
642 }
643 GeneratedAs::ByDefault => {
644 write!(f, "GENERATED BY DEFAULT AS IDENTITY")?;
645 if sequence_options.is_some() {
646 let so = sequence_options.as_ref().unwrap();
647 if !so.is_empty() {
648 write!(f, " (")?;
649 }
650 for sequence_option in so {
651 write!(f, "{sequence_option}")?;
652 }
653 if !so.is_empty() {
654 write!(f, " )")?;
655 }
656 }
657 Ok(())
658 }
659 GeneratedAs::ExpStored => {
660 let expr = generation_expr.as_ref().unwrap();
661 write!(f, "GENERATED ALWAYS AS ({expr}) STORED")
662 }
663 },
664 }
665 }
666}
667
668#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
671#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
672#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
673pub enum GeneratedAs {
674 Always,
675 ByDefault,
676 ExpStored,
677}
678
679fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
680 struct ConstraintName<'a>(&'a Option<Ident>);
681 impl<'a> fmt::Display for ConstraintName<'a> {
682 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
683 if let Some(name) = self.0 {
684 write!(f, "CONSTRAINT {name} ")?;
685 }
686 Ok(())
687 }
688 }
689 ConstraintName(name)
690}
691
692#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
697#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
698#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
699pub enum ReferentialAction {
700 Restrict,
701 Cascade,
702 SetNull,
703 NoAction,
704 SetDefault,
705}
706
707impl fmt::Display for ReferentialAction {
708 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
709 f.write_str(match self {
710 ReferentialAction::Restrict => "RESTRICT",
711 ReferentialAction::Cascade => "CASCADE",
712 ReferentialAction::SetNull => "SET NULL",
713 ReferentialAction::NoAction => "NO ACTION",
714 ReferentialAction::SetDefault => "SET DEFAULT",
715 })
716 }
717}