sqlparser/ast/
ddl.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13//! AST types specific to CREATE/ALTER variants of [`Statement`](crate::ast::Statement)
14//! (commonly referred to as Data Definition Language, or DDL)
15
16#[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    SqlOption,
30};
31use crate::tokenizer::Token;
32
33/// An `ALTER TABLE` (`Statement::AlterTable`) operation
34#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
37pub enum AlterTableOperation {
38    /// `ADD <table_constraint>`
39    AddConstraint(TableConstraint),
40    /// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
41    AddColumn {
42        /// `[COLUMN]`.
43        column_keyword: bool,
44        /// `[IF NOT EXISTS]`
45        if_not_exists: bool,
46        /// <column_def>.
47        column_def: ColumnDef,
48    },
49    /// `DISABLE ROW LEVEL SECURITY`
50    ///
51    /// Note: this is a PostgreSQL-specific operation.
52    DisableRowLevelSecurity,
53    /// `DISABLE RULE rewrite_rule_name`
54    ///
55    /// Note: this is a PostgreSQL-specific operation.
56    DisableRule { name: Ident },
57    /// `DISABLE TRIGGER [ trigger_name | ALL | USER ]`
58    ///
59    /// Note: this is a PostgreSQL-specific operation.
60    DisableTrigger { name: Ident },
61    /// `DROP CONSTRAINT [ IF EXISTS ] <name>`
62    DropConstraint {
63        if_exists: bool,
64        name: Ident,
65        cascade: bool,
66    },
67    /// `DROP [ COLUMN ] [ IF EXISTS ] <column_name> [ CASCADE ]`
68    DropColumn {
69        column_name: Ident,
70        if_exists: bool,
71        cascade: bool,
72    },
73    /// `DROP PRIMARY KEY`
74    ///
75    /// Note: this is a MySQL-specific operation.
76    DropPrimaryKey,
77    /// `ENABLE ALWAYS RULE rewrite_rule_name`
78    ///
79    /// Note: this is a PostgreSQL-specific operation.
80    EnableAlwaysRule { name: Ident },
81    /// `ENABLE ALWAYS TRIGGER trigger_name`
82    ///
83    /// Note: this is a PostgreSQL-specific operation.
84    EnableAlwaysTrigger { name: Ident },
85    /// `ENABLE REPLICA RULE rewrite_rule_name`
86    ///
87    /// Note: this is a PostgreSQL-specific operation.
88    EnableReplicaRule { name: Ident },
89    /// `ENABLE REPLICA TRIGGER trigger_name`
90    ///
91    /// Note: this is a PostgreSQL-specific operation.
92    EnableReplicaTrigger { name: Ident },
93    /// `ENABLE ROW LEVEL SECURITY`
94    ///
95    /// Note: this is a PostgreSQL-specific operation.
96    EnableRowLevelSecurity,
97    /// `ENABLE RULE rewrite_rule_name`
98    ///
99    /// Note: this is a PostgreSQL-specific operation.
100    EnableRule { name: Ident },
101    /// `ENABLE TRIGGER [ trigger_name | ALL | USER ]`
102    ///
103    /// Note: this is a PostgreSQL-specific operation.
104    EnableTrigger { name: Ident },
105    /// `RENAME TO PARTITION (partition=val)`
106    RenamePartitions {
107        old_partitions: Vec<Expr>,
108        new_partitions: Vec<Expr>,
109    },
110    /// Add Partitions
111    AddPartitions {
112        if_not_exists: bool,
113        new_partitions: Vec<Partition>,
114    },
115    DropPartitions {
116        partitions: Vec<Expr>,
117        if_exists: bool,
118    },
119    /// `RENAME [ COLUMN ] <old_column_name> TO <new_column_name>`
120    RenameColumn {
121        old_column_name: Ident,
122        new_column_name: Ident,
123    },
124    /// `RENAME TO <table_name>`
125    RenameTable { table_name: ObjectName },
126    // CHANGE [ COLUMN ] <old_name> <new_name> <data_type> [ <options> ]
127    ChangeColumn {
128        old_name: Ident,
129        new_name: Ident,
130        data_type: DataType,
131        options: Vec<ColumnOption>,
132    },
133    /// `RENAME CONSTRAINT <old_constraint_name> TO <new_constraint_name>`
134    ///
135    /// Note: this is a PostgreSQL-specific operation.
136    RenameConstraint { old_name: Ident, new_name: Ident },
137    /// `ALTER [ COLUMN ]`
138    AlterColumn {
139        column_name: Ident,
140        op: AlterColumnOperation,
141    },
142    /// 'SWAP WITH <table_name>'
143    ///
144    /// Note: this is Snowflake specific <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
145    SwapWith { table_name: ObjectName },
146}
147
148#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
149#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
150#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
151pub enum AlterIndexOperation {
152    RenameIndex { index_name: ObjectName },
153}
154
155impl fmt::Display for AlterTableOperation {
156    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
157        match self {
158            AlterTableOperation::AddPartitions {
159                if_not_exists,
160                new_partitions,
161            } => write!(
162                f,
163                "ADD{ine} {}",
164                display_separated(new_partitions, " "),
165                ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
166            ),
167            AlterTableOperation::AddConstraint(c) => write!(f, "ADD {c}"),
168            AlterTableOperation::AddColumn {
169                column_keyword,
170                if_not_exists,
171                column_def,
172            } => {
173                write!(f, "ADD")?;
174                if *column_keyword {
175                    write!(f, " COLUMN")?;
176                }
177                if *if_not_exists {
178                    write!(f, " IF NOT EXISTS")?;
179                }
180                write!(f, " {column_def}")?;
181
182                Ok(())
183            }
184            AlterTableOperation::AlterColumn { column_name, op } => {
185                write!(f, "ALTER COLUMN {column_name} {op}")
186            }
187            AlterTableOperation::DisableRowLevelSecurity => {
188                write!(f, "DISABLE ROW LEVEL SECURITY")
189            }
190            AlterTableOperation::DisableRule { name } => {
191                write!(f, "DISABLE RULE {name}")
192            }
193            AlterTableOperation::DisableTrigger { name } => {
194                write!(f, "DISABLE TRIGGER {name}")
195            }
196            AlterTableOperation::DropPartitions {
197                partitions,
198                if_exists,
199            } => write!(
200                f,
201                "DROP{ie} PARTITION ({})",
202                display_comma_separated(partitions),
203                ie = if *if_exists { " IF EXISTS" } else { "" }
204            ),
205            AlterTableOperation::DropConstraint {
206                if_exists,
207                name,
208                cascade,
209            } => {
210                write!(
211                    f,
212                    "DROP CONSTRAINT {}{}{}",
213                    if *if_exists { "IF EXISTS " } else { "" },
214                    name,
215                    if *cascade { " CASCADE" } else { "" },
216                )
217            }
218            AlterTableOperation::DropPrimaryKey => write!(f, "DROP PRIMARY KEY"),
219            AlterTableOperation::DropColumn {
220                column_name,
221                if_exists,
222                cascade,
223            } => write!(
224                f,
225                "DROP COLUMN {}{}{}",
226                if *if_exists { "IF EXISTS " } else { "" },
227                column_name,
228                if *cascade { " CASCADE" } else { "" }
229            ),
230            AlterTableOperation::EnableAlwaysRule { name } => {
231                write!(f, "ENABLE ALWAYS RULE {name}")
232            }
233            AlterTableOperation::EnableAlwaysTrigger { name } => {
234                write!(f, "ENABLE ALWAYS TRIGGER {name}")
235            }
236            AlterTableOperation::EnableReplicaRule { name } => {
237                write!(f, "ENABLE REPLICA RULE {name}")
238            }
239            AlterTableOperation::EnableReplicaTrigger { name } => {
240                write!(f, "ENABLE REPLICA TRIGGER {name}")
241            }
242            AlterTableOperation::EnableRowLevelSecurity => {
243                write!(f, "ENABLE ROW LEVEL SECURITY")
244            }
245            AlterTableOperation::EnableRule { name } => {
246                write!(f, "ENABLE RULE {name}")
247            }
248            AlterTableOperation::EnableTrigger { name } => {
249                write!(f, "ENABLE TRIGGER {name}")
250            }
251            AlterTableOperation::RenamePartitions {
252                old_partitions,
253                new_partitions,
254            } => write!(
255                f,
256                "PARTITION ({}) RENAME TO PARTITION ({})",
257                display_comma_separated(old_partitions),
258                display_comma_separated(new_partitions)
259            ),
260            AlterTableOperation::RenameColumn {
261                old_column_name,
262                new_column_name,
263            } => write!(f, "RENAME COLUMN {old_column_name} TO {new_column_name}"),
264            AlterTableOperation::RenameTable { table_name } => {
265                write!(f, "RENAME TO {table_name}")
266            }
267            AlterTableOperation::ChangeColumn {
268                old_name,
269                new_name,
270                data_type,
271                options,
272            } => {
273                write!(f, "CHANGE COLUMN {old_name} {new_name} {data_type}")?;
274                if options.is_empty() {
275                    Ok(())
276                } else {
277                    write!(f, " {}", display_separated(options, " "))
278                }
279            }
280            AlterTableOperation::RenameConstraint { old_name, new_name } => {
281                write!(f, "RENAME CONSTRAINT {old_name} TO {new_name}")
282            }
283            AlterTableOperation::SwapWith { table_name } => {
284                write!(f, "SWAP WITH {table_name}")
285            }
286        }
287    }
288}
289
290impl fmt::Display for AlterIndexOperation {
291    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
292        match self {
293            AlterIndexOperation::RenameIndex { index_name } => {
294                write!(f, "RENAME TO {index_name}")
295            }
296        }
297    }
298}
299
300/// An `ALTER COLUMN` (`Statement::AlterTable`) operation
301#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
302#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
303#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
304pub enum AlterColumnOperation {
305    /// `SET NOT NULL`
306    SetNotNull,
307    /// `DROP NOT NULL`
308    DropNotNull,
309    /// `SET DEFAULT <expr>`
310    SetDefault { value: Expr },
311    /// `DROP DEFAULT`
312    DropDefault,
313    /// `[SET DATA] TYPE <data_type> [USING <expr>]`
314    SetDataType {
315        data_type: DataType,
316        /// PostgreSQL specific
317        using: Option<Expr>,
318    },
319    /// `ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]`
320    ///
321    /// Note: this is a PostgreSQL-specific operation.
322    AddGenerated {
323        generated_as: Option<GeneratedAs>,
324        sequence_options: Option<Vec<SequenceOptions>>,
325    },
326}
327
328impl fmt::Display for AlterColumnOperation {
329    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
330        match self {
331            AlterColumnOperation::SetNotNull => write!(f, "SET NOT NULL",),
332            AlterColumnOperation::DropNotNull => write!(f, "DROP NOT NULL",),
333            AlterColumnOperation::SetDefault { value } => {
334                write!(f, "SET DEFAULT {value}")
335            }
336            AlterColumnOperation::DropDefault {} => {
337                write!(f, "DROP DEFAULT")
338            }
339            AlterColumnOperation::SetDataType { data_type, using } => {
340                if let Some(expr) = using {
341                    write!(f, "SET DATA TYPE {data_type} USING {expr}")
342                } else {
343                    write!(f, "SET DATA TYPE {data_type}")
344                }
345            }
346            AlterColumnOperation::AddGenerated {
347                generated_as,
348                sequence_options,
349            } => {
350                let generated_as = match generated_as {
351                    Some(GeneratedAs::Always) => " ALWAYS",
352                    Some(GeneratedAs::ByDefault) => " BY DEFAULT",
353                    _ => "",
354                };
355
356                write!(f, "ADD GENERATED{generated_as} AS IDENTITY",)?;
357                if let Some(options) = sequence_options {
358                    write!(f, " (")?;
359
360                    for sequence_option in options {
361                        write!(f, "{sequence_option}")?;
362                    }
363
364                    write!(f, " )")?;
365                }
366                Ok(())
367            }
368        }
369    }
370}
371
372/// A table-level constraint, specified in a `CREATE TABLE` or an
373/// `ALTER TABLE ADD <constraint>` statement.
374#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
375#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
376#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
377pub enum TableConstraint {
378    /// `[ CONSTRAINT <name> ] { PRIMARY KEY | UNIQUE } (<columns>)`
379    Unique {
380        name: Option<Ident>,
381        columns: Vec<Ident>,
382        /// Whether this is a `PRIMARY KEY` or just a `UNIQUE` constraint
383        is_primary: bool,
384        characteristics: Option<ConstraintCharacteristics>,
385    },
386    /// A referential integrity constraint (`[ CONSTRAINT <name> ] FOREIGN KEY (<columns>)
387    /// REFERENCES <foreign_table> (<referred_columns>)
388    /// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
389    ///   [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
390    /// }`).
391    ForeignKey {
392        name: Option<Ident>,
393        columns: Vec<Ident>,
394        foreign_table: ObjectName,
395        referred_columns: Vec<Ident>,
396        on_delete: Option<ReferentialAction>,
397        on_update: Option<ReferentialAction>,
398        characteristics: Option<ConstraintCharacteristics>,
399    },
400    /// `[ CONSTRAINT <name> ] CHECK (<expr>)`
401    Check {
402        name: Option<Ident>,
403        expr: Box<Expr>,
404    },
405    /// MySQLs [index definition][1] for index creation. Not present on ANSI so, for now, the usage
406    /// is restricted to MySQL, as no other dialects that support this syntax were found.
407    ///
408    /// `{INDEX | KEY} [index_name] [index_type] (key_part,...) [index_option]...`
409    ///
410    /// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
411    Index {
412        /// Whether this index starts with KEY (true) or INDEX (false), to maintain the same syntax.
413        display_as_key: bool,
414        /// Index name.
415        name: Option<Ident>,
416        /// Optional [index type][1].
417        ///
418        /// [1]: IndexType
419        index_type: Option<IndexType>,
420        /// Referred column identifier list.
421        columns: Vec<Ident>,
422    },
423    /// MySQLs [fulltext][1] definition. Since the [`SPATIAL`][2] definition is exactly the same,
424    /// and MySQL displays both the same way, it is part of this definition as well.
425    ///
426    /// Supported syntax:
427    ///
428    /// ```markdown
429    /// {FULLTEXT | SPATIAL} [INDEX | KEY] [index_name] (key_part,...)
430    ///
431    /// key_part: col_name
432    /// ```
433    ///
434    /// [1]: https://dev.mysql.com/doc/refman/8.0/en/fulltext-natural-language.html
435    /// [2]: https://dev.mysql.com/doc/refman/8.0/en/spatial-types.html
436    FulltextOrSpatial {
437        /// Whether this is a `FULLTEXT` (true) or `SPATIAL` (false) definition.
438        fulltext: bool,
439        /// Whether the type is followed by the keyword `KEY`, `INDEX`, or no keyword at all.
440        index_type_display: KeyOrIndexDisplay,
441        /// Optional index name.
442        opt_index_name: Option<Ident>,
443        /// Referred column identifier list.
444        columns: Vec<Ident>,
445    },
446}
447
448impl fmt::Display for TableConstraint {
449    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
450        match self {
451            TableConstraint::Unique {
452                name,
453                columns,
454                is_primary,
455                characteristics,
456            } => {
457                write!(
458                    f,
459                    "{}{} ({})",
460                    display_constraint_name(name),
461                    if *is_primary { "PRIMARY KEY" } else { "UNIQUE" },
462                    display_comma_separated(columns)
463                )?;
464
465                if let Some(characteristics) = characteristics {
466                    write!(f, " {}", characteristics)?;
467                }
468
469                Ok(())
470            }
471            TableConstraint::ForeignKey {
472                name,
473                columns,
474                foreign_table,
475                referred_columns,
476                on_delete,
477                on_update,
478                characteristics,
479            } => {
480                write!(
481                    f,
482                    "{}FOREIGN KEY ({}) REFERENCES {}({})",
483                    display_constraint_name(name),
484                    display_comma_separated(columns),
485                    foreign_table,
486                    display_comma_separated(referred_columns),
487                )?;
488                if let Some(action) = on_delete {
489                    write!(f, " ON DELETE {action}")?;
490                }
491                if let Some(action) = on_update {
492                    write!(f, " ON UPDATE {action}")?;
493                }
494                if let Some(characteristics) = characteristics {
495                    write!(f, " {}", characteristics)?;
496                }
497                Ok(())
498            }
499            TableConstraint::Check { name, expr } => {
500                write!(f, "{}CHECK ({})", display_constraint_name(name), expr)
501            }
502            TableConstraint::Index {
503                display_as_key,
504                name,
505                index_type,
506                columns,
507            } => {
508                write!(f, "{}", if *display_as_key { "KEY" } else { "INDEX" })?;
509                if let Some(name) = name {
510                    write!(f, " {name}")?;
511                }
512                if let Some(index_type) = index_type {
513                    write!(f, " USING {index_type}")?;
514                }
515                write!(f, " ({})", display_comma_separated(columns))?;
516
517                Ok(())
518            }
519            Self::FulltextOrSpatial {
520                fulltext,
521                index_type_display,
522                opt_index_name,
523                columns,
524            } => {
525                if *fulltext {
526                    write!(f, "FULLTEXT")?;
527                } else {
528                    write!(f, "SPATIAL")?;
529                }
530
531                if !matches!(index_type_display, KeyOrIndexDisplay::None) {
532                    write!(f, " {index_type_display}")?;
533                }
534
535                if let Some(name) = opt_index_name {
536                    write!(f, " {name}")?;
537                }
538
539                write!(f, " ({})", display_comma_separated(columns))?;
540
541                Ok(())
542            }
543        }
544    }
545}
546
547/// Representation whether a definition can can contains the KEY or INDEX keywords with the same
548/// meaning.
549///
550/// This enum initially is directed to `FULLTEXT`,`SPATIAL`, and `UNIQUE` indexes on create table
551/// statements of `MySQL` [(1)].
552///
553/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
554#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
555#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
556#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
557pub enum KeyOrIndexDisplay {
558    /// Nothing to display
559    None,
560    /// Display the KEY keyword
561    Key,
562    /// Display the INDEX keyword
563    Index,
564}
565
566impl fmt::Display for KeyOrIndexDisplay {
567    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
568        match self {
569            KeyOrIndexDisplay::None => {
570                write!(f, "")
571            }
572            KeyOrIndexDisplay::Key => {
573                write!(f, "KEY")
574            }
575            KeyOrIndexDisplay::Index => {
576                write!(f, "INDEX")
577            }
578        }
579    }
580}
581
582/// Indexing method used by that index.
583///
584/// This structure isn't present on ANSI, but is found at least in [`MySQL` CREATE TABLE][1],
585/// [`MySQL` CREATE INDEX][2], and [Postgresql CREATE INDEX][3] statements.
586///
587/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
588/// [2]: https://dev.mysql.com/doc/refman/8.0/en/create-index.html
589/// [3]: https://www.postgresql.org/docs/14/sql-createindex.html
590#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
591#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
592#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
593pub enum IndexType {
594    BTree,
595    Hash,
596    // TODO add Postgresql's possible indexes
597}
598
599impl fmt::Display for IndexType {
600    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
601        match self {
602            Self::BTree => write!(f, "BTREE"),
603            Self::Hash => write!(f, "HASH"),
604        }
605    }
606}
607#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
608#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
609#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
610pub struct ProcedureParam {
611    pub name: Ident,
612    pub data_type: DataType,
613}
614
615impl fmt::Display for ProcedureParam {
616    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
617        write!(f, "{} {}", self.name, self.data_type)
618    }
619}
620
621/// SQL column definition
622#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
623#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
624#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
625pub struct ColumnDef {
626    pub name: Ident,
627    pub data_type: DataType,
628    pub collation: Option<ObjectName>,
629    pub options: Vec<ColumnOptionDef>,
630}
631
632impl fmt::Display for ColumnDef {
633    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
634        if self.data_type == DataType::Unspecified {
635            write!(f, "{}", self.name)?;
636        } else {
637            write!(f, "{} {}", self.name, self.data_type)?;
638        }
639        if let Some(collation) = &self.collation {
640            write!(f, " COLLATE {collation}")?;
641        }
642        for option in &self.options {
643            write!(f, " {option}")?;
644        }
645        Ok(())
646    }
647}
648
649/// Column definition specified in a `CREATE VIEW` statement.
650///
651/// Syntax
652/// ```markdown
653/// <name> [OPTIONS(option, ...)]
654///
655/// option: <name> = <value>
656/// ```
657///
658/// Examples:
659/// ```sql
660/// name
661/// age OPTIONS(description = "age column", tag = "prod")
662/// ```
663#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
664#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
665#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
666pub struct ViewColumnDef {
667    pub name: Ident,
668    pub options: Option<Vec<SqlOption>>,
669}
670
671impl fmt::Display for ViewColumnDef {
672    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
673        write!(f, "{}", self.name)?;
674        if let Some(options) = self.options.as_ref() {
675            write!(
676                f,
677                " OPTIONS({})",
678                display_comma_separated(options.as_slice())
679            )?;
680        }
681        Ok(())
682    }
683}
684
685/// An optionally-named `ColumnOption`: `[ CONSTRAINT <name> ] <column-option>`.
686///
687/// Note that implementations are substantially more permissive than the ANSI
688/// specification on what order column options can be presented in, and whether
689/// they are allowed to be named. The specification distinguishes between
690/// constraints (NOT NULL, UNIQUE, PRIMARY KEY, and CHECK), which can be named
691/// and can appear in any order, and other options (DEFAULT, GENERATED), which
692/// cannot be named and must appear in a fixed order. `PostgreSQL`, however,
693/// allows preceding any option with `CONSTRAINT <name>`, even those that are
694/// not really constraints, like NULL and DEFAULT. MSSQL is less permissive,
695/// allowing DEFAULT, UNIQUE, PRIMARY KEY and CHECK to be named, but not NULL or
696/// NOT NULL constraints (the last of which is in violation of the spec).
697///
698/// For maximum flexibility, we don't distinguish between constraint and
699/// non-constraint options, lumping them all together under the umbrella of
700/// "column options," and we allow any column option to be named.
701#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
702#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
703#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
704pub struct ColumnOptionDef {
705    pub name: Option<Ident>,
706    pub option: ColumnOption,
707}
708
709impl fmt::Display for ColumnOptionDef {
710    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
711        write!(f, "{}{}", display_constraint_name(&self.name), self.option)
712    }
713}
714
715/// `ColumnOption`s are modifiers that follow a column definition in a `CREATE
716/// TABLE` statement.
717#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
718#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
719#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
720pub enum ColumnOption {
721    /// `NULL`
722    Null,
723    /// `NOT NULL`
724    NotNull,
725    /// `DEFAULT <restricted-expr>`
726    Default(Expr),
727    /// `{ PRIMARY KEY | UNIQUE } [<constraint_characteristics>]`
728    Unique {
729        is_primary: bool,
730        characteristics: Option<ConstraintCharacteristics>,
731    },
732    /// A referential integrity constraint (`[FOREIGN KEY REFERENCES
733    /// <foreign_table> (<referred_columns>)
734    /// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
735    ///   [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
736    /// }
737    /// [<constraint_characteristics>]
738    /// `).
739    ForeignKey {
740        foreign_table: ObjectName,
741        referred_columns: Vec<Ident>,
742        on_delete: Option<ReferentialAction>,
743        on_update: Option<ReferentialAction>,
744        characteristics: Option<ConstraintCharacteristics>,
745    },
746    /// `CHECK (<expr>)`
747    Check(Expr),
748    /// Dialect-specific options, such as:
749    /// - MySQL's `AUTO_INCREMENT` or SQLite's `AUTOINCREMENT`
750    /// - ...
751    DialectSpecific(Vec<Token>),
752    CharacterSet(ObjectName),
753    Comment(String),
754    OnUpdate(Expr),
755    /// `Generated`s are modifiers that follow a column definition in a `CREATE
756    /// TABLE` statement.
757    Generated {
758        generated_as: GeneratedAs,
759        sequence_options: Option<Vec<SequenceOptions>>,
760        generation_expr: Option<Expr>,
761        generation_expr_mode: Option<GeneratedExpressionMode>,
762        /// false if 'GENERATED ALWAYS' is skipped (option starts with AS)
763        generated_keyword: bool,
764    },
765    /// BigQuery specific: Explicit column options in a view [1] or table [2]
766    /// Syntax
767    /// ```sql
768    /// OPTIONS(description="field desc")
769    /// ```
770    /// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#view_column_option_list
771    /// [2]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#column_option_list
772    Options(Vec<SqlOption>),
773}
774
775impl fmt::Display for ColumnOption {
776    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
777        use ColumnOption::*;
778        match self {
779            Null => write!(f, "NULL"),
780            NotNull => write!(f, "NOT NULL"),
781            Default(expr) => write!(f, "DEFAULT {expr}"),
782            Unique {
783                is_primary,
784                characteristics,
785            } => {
786                write!(f, "{}", if *is_primary { "PRIMARY KEY" } else { "UNIQUE" })?;
787                if let Some(characteristics) = characteristics {
788                    write!(f, " {}", characteristics)?;
789                }
790                Ok(())
791            }
792            ForeignKey {
793                foreign_table,
794                referred_columns,
795                on_delete,
796                on_update,
797                characteristics,
798            } => {
799                write!(f, "REFERENCES {foreign_table}")?;
800                if !referred_columns.is_empty() {
801                    write!(f, " ({})", display_comma_separated(referred_columns))?;
802                }
803                if let Some(action) = on_delete {
804                    write!(f, " ON DELETE {action}")?;
805                }
806                if let Some(action) = on_update {
807                    write!(f, " ON UPDATE {action}")?;
808                }
809                if let Some(characteristics) = characteristics {
810                    write!(f, " {}", characteristics)?;
811                }
812                Ok(())
813            }
814            Check(expr) => write!(f, "CHECK ({expr})"),
815            DialectSpecific(val) => write!(f, "{}", display_separated(val, " ")),
816            CharacterSet(n) => write!(f, "CHARACTER SET {n}"),
817            Comment(v) => write!(f, "COMMENT '{}'", escape_single_quote_string(v)),
818            OnUpdate(expr) => write!(f, "ON UPDATE {expr}"),
819            Generated {
820                generated_as,
821                sequence_options,
822                generation_expr,
823                generation_expr_mode,
824                generated_keyword,
825            } => {
826                if let Some(expr) = generation_expr {
827                    let modifier = match generation_expr_mode {
828                        None => "",
829                        Some(GeneratedExpressionMode::Virtual) => " VIRTUAL",
830                        Some(GeneratedExpressionMode::Stored) => " STORED",
831                    };
832                    if *generated_keyword {
833                        write!(f, "GENERATED ALWAYS AS ({expr}){modifier}")?;
834                    } else {
835                        write!(f, "AS ({expr}){modifier}")?;
836                    }
837                    Ok(())
838                } else {
839                    // Like Postgres - generated from sequence
840                    let when = match generated_as {
841                        GeneratedAs::Always => "ALWAYS",
842                        GeneratedAs::ByDefault => "BY DEFAULT",
843                        // ExpStored goes with an expression, handled above
844                        GeneratedAs::ExpStored => unreachable!(),
845                    };
846                    write!(f, "GENERATED {when} AS IDENTITY")?;
847                    if sequence_options.is_some() {
848                        let so = sequence_options.as_ref().unwrap();
849                        if !so.is_empty() {
850                            write!(f, " (")?;
851                        }
852                        for sequence_option in so {
853                            write!(f, "{sequence_option}")?;
854                        }
855                        if !so.is_empty() {
856                            write!(f, " )")?;
857                        }
858                    }
859                    Ok(())
860                }
861            }
862            Options(options) => {
863                write!(f, "OPTIONS({})", display_comma_separated(options))
864            }
865        }
866    }
867}
868
869/// `GeneratedAs`s are modifiers that follow a column option in a `generated`.
870/// 'ExpStored' is used for a column generated from an expression and stored.
871#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
872#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
873#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
874pub enum GeneratedAs {
875    Always,
876    ByDefault,
877    ExpStored,
878}
879
880/// `GeneratedExpressionMode`s are modifiers that follow an expression in a `generated`.
881/// No modifier is typically the same as Virtual.
882#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
883#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
884#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
885pub enum GeneratedExpressionMode {
886    Virtual,
887    Stored,
888}
889
890fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
891    struct ConstraintName<'a>(&'a Option<Ident>);
892    impl<'a> fmt::Display for ConstraintName<'a> {
893        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
894            if let Some(name) = self.0 {
895                write!(f, "CONSTRAINT {name} ")?;
896            }
897            Ok(())
898        }
899    }
900    ConstraintName(name)
901}
902
903/// `<constraint_characteristics> = [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ]`
904///
905/// Used in UNIQUE and foreign key constraints. The individual settings may occur in any order.
906#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
907#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
908#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
909pub struct ConstraintCharacteristics {
910    /// `[ DEFERRABLE | NOT DEFERRABLE ]`
911    pub deferrable: Option<bool>,
912    /// `[ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]`
913    pub initially: Option<DeferrableInitial>,
914    /// `[ ENFORCED | NOT ENFORCED ]`
915    pub enforced: Option<bool>,
916}
917
918#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
919#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
920#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
921pub enum DeferrableInitial {
922    /// `INITIALLY IMMEDIATE`
923    Immediate,
924    /// `INITIALLY DEFERRED`
925    Deferred,
926}
927
928impl ConstraintCharacteristics {
929    fn deferrable_text(&self) -> Option<&'static str> {
930        self.deferrable.map(|deferrable| {
931            if deferrable {
932                "DEFERRABLE"
933            } else {
934                "NOT DEFERRABLE"
935            }
936        })
937    }
938
939    fn initially_immediate_text(&self) -> Option<&'static str> {
940        self.initially
941            .map(|initially_immediate| match initially_immediate {
942                DeferrableInitial::Immediate => "INITIALLY IMMEDIATE",
943                DeferrableInitial::Deferred => "INITIALLY DEFERRED",
944            })
945    }
946
947    fn enforced_text(&self) -> Option<&'static str> {
948        self.enforced.map(
949            |enforced| {
950                if enforced {
951                    "ENFORCED"
952                } else {
953                    "NOT ENFORCED"
954                }
955            },
956        )
957    }
958}
959
960impl fmt::Display for ConstraintCharacteristics {
961    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
962        let deferrable = self.deferrable_text();
963        let initially_immediate = self.initially_immediate_text();
964        let enforced = self.enforced_text();
965
966        match (deferrable, initially_immediate, enforced) {
967            (None, None, None) => Ok(()),
968            (None, None, Some(enforced)) => write!(f, "{enforced}"),
969            (None, Some(initial), None) => write!(f, "{initial}"),
970            (None, Some(initial), Some(enforced)) => write!(f, "{initial} {enforced}"),
971            (Some(deferrable), None, None) => write!(f, "{deferrable}"),
972            (Some(deferrable), None, Some(enforced)) => write!(f, "{deferrable} {enforced}"),
973            (Some(deferrable), Some(initial), None) => write!(f, "{deferrable} {initial}"),
974            (Some(deferrable), Some(initial), Some(enforced)) => {
975                write!(f, "{deferrable} {initial} {enforced}")
976            }
977        }
978    }
979}
980
981/// `<referential_action> =
982/// { RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT }`
983///
984/// Used in foreign key constraints in `ON UPDATE` and `ON DELETE` options.
985#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
986#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
987#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
988pub enum ReferentialAction {
989    Restrict,
990    Cascade,
991    SetNull,
992    NoAction,
993    SetDefault,
994}
995
996impl fmt::Display for ReferentialAction {
997    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
998        f.write_str(match self {
999            ReferentialAction::Restrict => "RESTRICT",
1000            ReferentialAction::Cascade => "CASCADE",
1001            ReferentialAction::SetNull => "SET NULL",
1002            ReferentialAction::NoAction => "NO ACTION",
1003            ReferentialAction::SetDefault => "SET DEFAULT",
1004        })
1005    }
1006}
1007
1008/// SQL user defined type definition
1009#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1010#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1011#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1012pub enum UserDefinedTypeRepresentation {
1013    Composite {
1014        attributes: Vec<UserDefinedTypeCompositeAttributeDef>,
1015    },
1016}
1017
1018impl fmt::Display for UserDefinedTypeRepresentation {
1019    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1020        match self {
1021            UserDefinedTypeRepresentation::Composite { attributes } => {
1022                write!(f, "({})", display_comma_separated(attributes))
1023            }
1024        }
1025    }
1026}
1027
1028/// SQL user defined type attribute definition
1029#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1030#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1031#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1032pub struct UserDefinedTypeCompositeAttributeDef {
1033    pub name: Ident,
1034    pub data_type: DataType,
1035    pub collation: Option<ObjectName>,
1036}
1037
1038impl fmt::Display for UserDefinedTypeCompositeAttributeDef {
1039    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1040        write!(f, "{} {}", self.name, self.data_type)?;
1041        if let Some(collation) = &self.collation {
1042            write!(f, " COLLATE {collation}")?;
1043        }
1044        Ok(())
1045    }
1046}
1047
1048/// PARTITION statement used in ALTER TABLE et al. such as in Hive SQL
1049#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1050#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1051#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1052pub struct Partition {
1053    pub partitions: Vec<Expr>,
1054}
1055
1056impl fmt::Display for Partition {
1057    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1058        write!(
1059            f,
1060            "PARTITION ({})",
1061            display_comma_separated(&self.partitions)
1062        )
1063    }
1064}