Thanks to visit codestin.com
Credit goes to docs.rs

sqlparser/ast/
ddl.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! AST types specific to CREATE/ALTER variants of [`Statement`](crate::ast::Statement)
19//! (commonly referred to as Data Definition Language, or DDL)
20
21#[cfg(not(feature = "std"))]
22use alloc::{boxed::Box, string::String, vec::Vec};
23use core::fmt::{self, Display, Write};
24
25#[cfg(feature = "serde")]
26use serde::{Deserialize, Serialize};
27
28#[cfg(feature = "visitor")]
29use sqlparser_derive::{Visit, VisitMut};
30
31use crate::ast::value::escape_single_quote_string;
32use crate::ast::{
33    display_comma_separated, display_separated, ArgMode, CommentDef, ConditionalStatements,
34    CreateFunctionBody, CreateFunctionUsing, CreateTableLikeKind, CreateTableOptions, DataType,
35    Expr, FileFormat, FunctionBehavior, FunctionCalledOnNull, FunctionDeterminismSpecifier,
36    FunctionParallel, HiveDistributionStyle, HiveFormat, HiveIOFormat, HiveRowFormat, Ident,
37    InitializeKind, MySQLColumnPosition, ObjectName, OnCommit, OneOrManyWithParens,
38    OperateFunctionArg, OrderByExpr, ProjectionSelect, Query, RefreshModeKind, RowAccessPolicy,
39    SequenceOptions, Spanned, SqlOption, StorageSerializationPolicy, TableVersion, Tag,
40    TriggerEvent, TriggerExecBody, TriggerObject, TriggerPeriod, TriggerReferencing, Value,
41    ValueWithSpan, WrappedCollection,
42};
43use crate::display_utils::{DisplayCommaSeparated, Indent, NewLine, SpaceOrNewline};
44use crate::keywords::Keyword;
45use crate::tokenizer::{Span, Token};
46
47/// Index column type.
48#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
49#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
50#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
51pub struct IndexColumn {
52    pub column: OrderByExpr,
53    pub operator_class: Option<Ident>,
54}
55
56impl fmt::Display for IndexColumn {
57    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58        write!(f, "{}", self.column)?;
59        if let Some(operator_class) = &self.operator_class {
60            write!(f, " {operator_class}")?;
61        }
62        Ok(())
63    }
64}
65
66/// ALTER TABLE operation REPLICA IDENTITY values
67/// See [Postgres ALTER TABLE docs](https://www.postgresql.org/docs/current/sql-altertable.html)
68#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
69#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
70#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
71pub enum ReplicaIdentity {
72    None,
73    Full,
74    Default,
75    Index(Ident),
76}
77
78impl fmt::Display for ReplicaIdentity {
79    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80        match self {
81            ReplicaIdentity::None => f.write_str("NONE"),
82            ReplicaIdentity::Full => f.write_str("FULL"),
83            ReplicaIdentity::Default => f.write_str("DEFAULT"),
84            ReplicaIdentity::Index(idx) => write!(f, "USING INDEX {idx}"),
85        }
86    }
87}
88
89/// An `ALTER TABLE` (`Statement::AlterTable`) operation
90#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
91#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
92#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
93pub enum AlterTableOperation {
94    /// `ADD <table_constraint> [NOT VALID]`
95    AddConstraint {
96        constraint: TableConstraint,
97        not_valid: bool,
98    },
99    /// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
100    AddColumn {
101        /// `[COLUMN]`.
102        column_keyword: bool,
103        /// `[IF NOT EXISTS]`
104        if_not_exists: bool,
105        /// <column_def>.
106        column_def: ColumnDef,
107        /// MySQL `ALTER TABLE` only  [FIRST | AFTER column_name]
108        column_position: Option<MySQLColumnPosition>,
109    },
110    /// `ADD PROJECTION [IF NOT EXISTS] name ( SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY])`
111    ///
112    /// Note: this is a ClickHouse-specific operation.
113    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#add-projection)
114    AddProjection {
115        if_not_exists: bool,
116        name: Ident,
117        select: ProjectionSelect,
118    },
119    /// `DROP PROJECTION [IF EXISTS] name`
120    ///
121    /// Note: this is a ClickHouse-specific operation.
122    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#drop-projection)
123    DropProjection {
124        if_exists: bool,
125        name: Ident,
126    },
127    /// `MATERIALIZE PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
128    ///
129    ///  Note: this is a ClickHouse-specific operation.
130    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#materialize-projection)
131    MaterializeProjection {
132        if_exists: bool,
133        name: Ident,
134        partition: Option<Ident>,
135    },
136    /// `CLEAR PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
137    ///
138    /// Note: this is a ClickHouse-specific operation.
139    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#clear-projection)
140    ClearProjection {
141        if_exists: bool,
142        name: Ident,
143        partition: Option<Ident>,
144    },
145    /// `DISABLE ROW LEVEL SECURITY`
146    ///
147    /// Note: this is a PostgreSQL-specific operation.
148    DisableRowLevelSecurity,
149    /// `DISABLE RULE rewrite_rule_name`
150    ///
151    /// Note: this is a PostgreSQL-specific operation.
152    DisableRule {
153        name: Ident,
154    },
155    /// `DISABLE TRIGGER [ trigger_name | ALL | USER ]`
156    ///
157    /// Note: this is a PostgreSQL-specific operation.
158    DisableTrigger {
159        name: Ident,
160    },
161    /// `DROP CONSTRAINT [ IF EXISTS ] <name>`
162    DropConstraint {
163        if_exists: bool,
164        name: Ident,
165        drop_behavior: Option<DropBehavior>,
166    },
167    /// `DROP [ COLUMN ] [ IF EXISTS ] <column_name> [ , <column_name>, ... ] [ CASCADE ]`
168    DropColumn {
169        has_column_keyword: bool,
170        column_names: Vec<Ident>,
171        if_exists: bool,
172        drop_behavior: Option<DropBehavior>,
173    },
174    /// `ATTACH PART|PARTITION <partition_expr>`
175    /// Note: this is a ClickHouse-specific operation, please refer to
176    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
177    AttachPartition {
178        // PART is not a short form of PARTITION, it's a separate keyword
179        // which represents a physical file on disk and partition is a logical entity.
180        partition: Partition,
181    },
182    /// `DETACH PART|PARTITION <partition_expr>`
183    /// Note: this is a ClickHouse-specific operation, please refer to
184    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#detach-partitionpart)
185    DetachPartition {
186        // See `AttachPartition` for more details
187        partition: Partition,
188    },
189    /// `FREEZE PARTITION <partition_expr>`
190    /// Note: this is a ClickHouse-specific operation, please refer to
191    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#freeze-partition)
192    FreezePartition {
193        partition: Partition,
194        with_name: Option<Ident>,
195    },
196    /// `UNFREEZE PARTITION <partition_expr>`
197    /// Note: this is a ClickHouse-specific operation, please refer to
198    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#unfreeze-partition)
199    UnfreezePartition {
200        partition: Partition,
201        with_name: Option<Ident>,
202    },
203    /// `DROP PRIMARY KEY`
204    ///
205    /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/alter-table.html)
206    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constraints-drop)
207    DropPrimaryKey {
208        drop_behavior: Option<DropBehavior>,
209    },
210    /// `DROP FOREIGN KEY <fk_symbol>`
211    ///
212    /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/alter-table.html)
213    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constraints-drop)
214    DropForeignKey {
215        name: Ident,
216        drop_behavior: Option<DropBehavior>,
217    },
218    /// `DROP INDEX <index_name>`
219    ///
220    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
221    DropIndex {
222        name: Ident,
223    },
224    /// `ENABLE ALWAYS RULE rewrite_rule_name`
225    ///
226    /// Note: this is a PostgreSQL-specific operation.
227    EnableAlwaysRule {
228        name: Ident,
229    },
230    /// `ENABLE ALWAYS TRIGGER trigger_name`
231    ///
232    /// Note: this is a PostgreSQL-specific operation.
233    EnableAlwaysTrigger {
234        name: Ident,
235    },
236    /// `ENABLE REPLICA RULE rewrite_rule_name`
237    ///
238    /// Note: this is a PostgreSQL-specific operation.
239    EnableReplicaRule {
240        name: Ident,
241    },
242    /// `ENABLE REPLICA TRIGGER trigger_name`
243    ///
244    /// Note: this is a PostgreSQL-specific operation.
245    EnableReplicaTrigger {
246        name: Ident,
247    },
248    /// `ENABLE ROW LEVEL SECURITY`
249    ///
250    /// Note: this is a PostgreSQL-specific operation.
251    EnableRowLevelSecurity,
252    /// `ENABLE RULE rewrite_rule_name`
253    ///
254    /// Note: this is a PostgreSQL-specific operation.
255    EnableRule {
256        name: Ident,
257    },
258    /// `ENABLE TRIGGER [ trigger_name | ALL | USER ]`
259    ///
260    /// Note: this is a PostgreSQL-specific operation.
261    EnableTrigger {
262        name: Ident,
263    },
264    /// `RENAME TO PARTITION (partition=val)`
265    RenamePartitions {
266        old_partitions: Vec<Expr>,
267        new_partitions: Vec<Expr>,
268    },
269    /// REPLICA IDENTITY { DEFAULT | USING INDEX index_name | FULL | NOTHING }
270    ///
271    /// Note: this is a PostgreSQL-specific operation.
272    /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
273    ReplicaIdentity {
274        identity: ReplicaIdentity,
275    },
276    /// Add Partitions
277    AddPartitions {
278        if_not_exists: bool,
279        new_partitions: Vec<Partition>,
280    },
281    DropPartitions {
282        partitions: Vec<Expr>,
283        if_exists: bool,
284    },
285    /// `RENAME [ COLUMN ] <old_column_name> TO <new_column_name>`
286    RenameColumn {
287        old_column_name: Ident,
288        new_column_name: Ident,
289    },
290    /// `RENAME TO <table_name>`
291    RenameTable {
292        table_name: RenameTableNameKind,
293    },
294    // CHANGE [ COLUMN ] <old_name> <new_name> <data_type> [ <options> ]
295    ChangeColumn {
296        old_name: Ident,
297        new_name: Ident,
298        data_type: DataType,
299        options: Vec<ColumnOption>,
300        /// MySQL `ALTER TABLE` only  [FIRST | AFTER column_name]
301        column_position: Option<MySQLColumnPosition>,
302    },
303    // CHANGE [ COLUMN ] <col_name> <data_type> [ <options> ]
304    ModifyColumn {
305        col_name: Ident,
306        data_type: DataType,
307        options: Vec<ColumnOption>,
308        /// MySQL `ALTER TABLE` only  [FIRST | AFTER column_name]
309        column_position: Option<MySQLColumnPosition>,
310    },
311    /// `RENAME CONSTRAINT <old_constraint_name> TO <new_constraint_name>`
312    ///
313    /// Note: this is a PostgreSQL-specific operation.
314    RenameConstraint {
315        old_name: Ident,
316        new_name: Ident,
317    },
318    /// `ALTER [ COLUMN ]`
319    AlterColumn {
320        column_name: Ident,
321        op: AlterColumnOperation,
322    },
323    /// 'SWAP WITH <table_name>'
324    ///
325    /// Note: this is Snowflake specific <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
326    SwapWith {
327        table_name: ObjectName,
328    },
329    /// 'SET TBLPROPERTIES ( { property_key [ = ] property_val } [, ...] )'
330    SetTblProperties {
331        table_properties: Vec<SqlOption>,
332    },
333    /// `OWNER TO { <new_owner> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
334    ///
335    /// Note: this is PostgreSQL-specific <https://www.postgresql.org/docs/current/sql-altertable.html>
336    OwnerTo {
337        new_owner: Owner,
338    },
339    /// Snowflake table clustering options
340    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-table#clustering-actions-clusteringaction>
341    ClusterBy {
342        exprs: Vec<Expr>,
343    },
344    DropClusteringKey,
345    SuspendRecluster,
346    ResumeRecluster,
347    /// `ALGORITHM [=] { DEFAULT | INSTANT | INPLACE | COPY }`
348    ///
349    /// [MySQL]-specific table alter algorithm.
350    ///
351    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
352    Algorithm {
353        equals: bool,
354        algorithm: AlterTableAlgorithm,
355    },
356
357    /// `LOCK [=] { DEFAULT | NONE | SHARED | EXCLUSIVE }`
358    ///
359    /// [MySQL]-specific table alter lock.
360    ///
361    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
362    Lock {
363        equals: bool,
364        lock: AlterTableLock,
365    },
366    /// `AUTO_INCREMENT [=] <value>`
367    ///
368    /// [MySQL]-specific table option for raising current auto increment value.
369    ///
370    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
371    AutoIncrement {
372        equals: bool,
373        value: ValueWithSpan,
374    },
375    /// `VALIDATE CONSTRAINT <name>`
376    ValidateConstraint {
377        name: Ident,
378    },
379    /// Arbitrary parenthesized `SET` options.
380    ///
381    /// Example:
382    /// ```sql
383    /// SET (scale_factor = 0.01, threshold = 500)`
384    /// ```
385    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-altertable.html)
386    SetOptionsParens {
387        options: Vec<SqlOption>,
388    },
389}
390
391/// An `ALTER Policy` (`Statement::AlterPolicy`) operation
392///
393/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
394#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
395#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
396#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
397pub enum AlterPolicyOperation {
398    Rename {
399        new_name: Ident,
400    },
401    Apply {
402        to: Option<Vec<Owner>>,
403        using: Option<Expr>,
404        with_check: Option<Expr>,
405    },
406}
407
408impl fmt::Display for AlterPolicyOperation {
409    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
410        match self {
411            AlterPolicyOperation::Rename { new_name } => {
412                write!(f, " RENAME TO {new_name}")
413            }
414            AlterPolicyOperation::Apply {
415                to,
416                using,
417                with_check,
418            } => {
419                if let Some(to) = to {
420                    write!(f, " TO {}", display_comma_separated(to))?;
421                }
422                if let Some(using) = using {
423                    write!(f, " USING ({using})")?;
424                }
425                if let Some(with_check) = with_check {
426                    write!(f, " WITH CHECK ({with_check})")?;
427                }
428                Ok(())
429            }
430        }
431    }
432}
433
434/// [MySQL] `ALTER TABLE` algorithm.
435///
436/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
437#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
438#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
439#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
440pub enum AlterTableAlgorithm {
441    Default,
442    Instant,
443    Inplace,
444    Copy,
445}
446
447impl fmt::Display for AlterTableAlgorithm {
448    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
449        f.write_str(match self {
450            Self::Default => "DEFAULT",
451            Self::Instant => "INSTANT",
452            Self::Inplace => "INPLACE",
453            Self::Copy => "COPY",
454        })
455    }
456}
457
458/// [MySQL] `ALTER TABLE` lock.
459///
460/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
461#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
462#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
463#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
464pub enum AlterTableLock {
465    Default,
466    None,
467    Shared,
468    Exclusive,
469}
470
471impl fmt::Display for AlterTableLock {
472    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
473        f.write_str(match self {
474            Self::Default => "DEFAULT",
475            Self::None => "NONE",
476            Self::Shared => "SHARED",
477            Self::Exclusive => "EXCLUSIVE",
478        })
479    }
480}
481
482#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
483#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
484#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
485pub enum Owner {
486    Ident(Ident),
487    CurrentRole,
488    CurrentUser,
489    SessionUser,
490}
491
492impl fmt::Display for Owner {
493    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
494        match self {
495            Owner::Ident(ident) => write!(f, "{ident}"),
496            Owner::CurrentRole => write!(f, "CURRENT_ROLE"),
497            Owner::CurrentUser => write!(f, "CURRENT_USER"),
498            Owner::SessionUser => write!(f, "SESSION_USER"),
499        }
500    }
501}
502
503#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
504#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
505#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
506pub enum AlterConnectorOwner {
507    User(Ident),
508    Role(Ident),
509}
510
511impl fmt::Display for AlterConnectorOwner {
512    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
513        match self {
514            AlterConnectorOwner::User(ident) => write!(f, "USER {ident}"),
515            AlterConnectorOwner::Role(ident) => write!(f, "ROLE {ident}"),
516        }
517    }
518}
519
520#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
521#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
522#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
523pub enum AlterIndexOperation {
524    RenameIndex { index_name: ObjectName },
525}
526
527impl fmt::Display for AlterTableOperation {
528    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
529        match self {
530            AlterTableOperation::AddPartitions {
531                if_not_exists,
532                new_partitions,
533            } => write!(
534                f,
535                "ADD{ine} {}",
536                display_separated(new_partitions, " "),
537                ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
538            ),
539            AlterTableOperation::AddConstraint {
540                not_valid,
541                constraint,
542            } => {
543                write!(f, "ADD {constraint}")?;
544                if *not_valid {
545                    write!(f, " NOT VALID")?;
546                }
547                Ok(())
548            }
549            AlterTableOperation::AddColumn {
550                column_keyword,
551                if_not_exists,
552                column_def,
553                column_position,
554            } => {
555                write!(f, "ADD")?;
556                if *column_keyword {
557                    write!(f, " COLUMN")?;
558                }
559                if *if_not_exists {
560                    write!(f, " IF NOT EXISTS")?;
561                }
562                write!(f, " {column_def}")?;
563
564                if let Some(position) = column_position {
565                    write!(f, " {position}")?;
566                }
567
568                Ok(())
569            }
570            AlterTableOperation::AddProjection {
571                if_not_exists,
572                name,
573                select: query,
574            } => {
575                write!(f, "ADD PROJECTION")?;
576                if *if_not_exists {
577                    write!(f, " IF NOT EXISTS")?;
578                }
579                write!(f, " {name} ({query})")
580            }
581            AlterTableOperation::Algorithm { equals, algorithm } => {
582                write!(
583                    f,
584                    "ALGORITHM {}{}",
585                    if *equals { "= " } else { "" },
586                    algorithm
587                )
588            }
589            AlterTableOperation::DropProjection { if_exists, name } => {
590                write!(f, "DROP PROJECTION")?;
591                if *if_exists {
592                    write!(f, " IF EXISTS")?;
593                }
594                write!(f, " {name}")
595            }
596            AlterTableOperation::MaterializeProjection {
597                if_exists,
598                name,
599                partition,
600            } => {
601                write!(f, "MATERIALIZE PROJECTION")?;
602                if *if_exists {
603                    write!(f, " IF EXISTS")?;
604                }
605                write!(f, " {name}")?;
606                if let Some(partition) = partition {
607                    write!(f, " IN PARTITION {partition}")?;
608                }
609                Ok(())
610            }
611            AlterTableOperation::ClearProjection {
612                if_exists,
613                name,
614                partition,
615            } => {
616                write!(f, "CLEAR PROJECTION")?;
617                if *if_exists {
618                    write!(f, " IF EXISTS")?;
619                }
620                write!(f, " {name}")?;
621                if let Some(partition) = partition {
622                    write!(f, " IN PARTITION {partition}")?;
623                }
624                Ok(())
625            }
626            AlterTableOperation::AlterColumn { column_name, op } => {
627                write!(f, "ALTER COLUMN {column_name} {op}")
628            }
629            AlterTableOperation::DisableRowLevelSecurity => {
630                write!(f, "DISABLE ROW LEVEL SECURITY")
631            }
632            AlterTableOperation::DisableRule { name } => {
633                write!(f, "DISABLE RULE {name}")
634            }
635            AlterTableOperation::DisableTrigger { name } => {
636                write!(f, "DISABLE TRIGGER {name}")
637            }
638            AlterTableOperation::DropPartitions {
639                partitions,
640                if_exists,
641            } => write!(
642                f,
643                "DROP{ie} PARTITION ({})",
644                display_comma_separated(partitions),
645                ie = if *if_exists { " IF EXISTS" } else { "" }
646            ),
647            AlterTableOperation::DropConstraint {
648                if_exists,
649                name,
650                drop_behavior,
651            } => {
652                write!(
653                    f,
654                    "DROP CONSTRAINT {}{}",
655                    if *if_exists { "IF EXISTS " } else { "" },
656                    name
657                )?;
658                if let Some(drop_behavior) = drop_behavior {
659                    write!(f, " {drop_behavior}")?;
660                }
661                Ok(())
662            }
663            AlterTableOperation::DropPrimaryKey { drop_behavior } => {
664                write!(f, "DROP PRIMARY KEY")?;
665                if let Some(drop_behavior) = drop_behavior {
666                    write!(f, " {drop_behavior}")?;
667                }
668                Ok(())
669            }
670            AlterTableOperation::DropForeignKey {
671                name,
672                drop_behavior,
673            } => {
674                write!(f, "DROP FOREIGN KEY {name}")?;
675                if let Some(drop_behavior) = drop_behavior {
676                    write!(f, " {drop_behavior}")?;
677                }
678                Ok(())
679            }
680            AlterTableOperation::DropIndex { name } => write!(f, "DROP INDEX {name}"),
681            AlterTableOperation::DropColumn {
682                has_column_keyword,
683                column_names: column_name,
684                if_exists,
685                drop_behavior,
686            } => {
687                write!(
688                    f,
689                    "DROP {}{}{}",
690                    if *has_column_keyword { "COLUMN " } else { "" },
691                    if *if_exists { "IF EXISTS " } else { "" },
692                    display_comma_separated(column_name),
693                )?;
694                if let Some(drop_behavior) = drop_behavior {
695                    write!(f, " {drop_behavior}")?;
696                }
697                Ok(())
698            }
699            AlterTableOperation::AttachPartition { partition } => {
700                write!(f, "ATTACH {partition}")
701            }
702            AlterTableOperation::DetachPartition { partition } => {
703                write!(f, "DETACH {partition}")
704            }
705            AlterTableOperation::EnableAlwaysRule { name } => {
706                write!(f, "ENABLE ALWAYS RULE {name}")
707            }
708            AlterTableOperation::EnableAlwaysTrigger { name } => {
709                write!(f, "ENABLE ALWAYS TRIGGER {name}")
710            }
711            AlterTableOperation::EnableReplicaRule { name } => {
712                write!(f, "ENABLE REPLICA RULE {name}")
713            }
714            AlterTableOperation::EnableReplicaTrigger { name } => {
715                write!(f, "ENABLE REPLICA TRIGGER {name}")
716            }
717            AlterTableOperation::EnableRowLevelSecurity => {
718                write!(f, "ENABLE ROW LEVEL SECURITY")
719            }
720            AlterTableOperation::EnableRule { name } => {
721                write!(f, "ENABLE RULE {name}")
722            }
723            AlterTableOperation::EnableTrigger { name } => {
724                write!(f, "ENABLE TRIGGER {name}")
725            }
726            AlterTableOperation::RenamePartitions {
727                old_partitions,
728                new_partitions,
729            } => write!(
730                f,
731                "PARTITION ({}) RENAME TO PARTITION ({})",
732                display_comma_separated(old_partitions),
733                display_comma_separated(new_partitions)
734            ),
735            AlterTableOperation::RenameColumn {
736                old_column_name,
737                new_column_name,
738            } => write!(f, "RENAME COLUMN {old_column_name} TO {new_column_name}"),
739            AlterTableOperation::RenameTable { table_name } => {
740                write!(f, "RENAME {table_name}")
741            }
742            AlterTableOperation::ChangeColumn {
743                old_name,
744                new_name,
745                data_type,
746                options,
747                column_position,
748            } => {
749                write!(f, "CHANGE COLUMN {old_name} {new_name} {data_type}")?;
750                if !options.is_empty() {
751                    write!(f, " {}", display_separated(options, " "))?;
752                }
753                if let Some(position) = column_position {
754                    write!(f, " {position}")?;
755                }
756
757                Ok(())
758            }
759            AlterTableOperation::ModifyColumn {
760                col_name,
761                data_type,
762                options,
763                column_position,
764            } => {
765                write!(f, "MODIFY COLUMN {col_name} {data_type}")?;
766                if !options.is_empty() {
767                    write!(f, " {}", display_separated(options, " "))?;
768                }
769                if let Some(position) = column_position {
770                    write!(f, " {position}")?;
771                }
772
773                Ok(())
774            }
775            AlterTableOperation::RenameConstraint { old_name, new_name } => {
776                write!(f, "RENAME CONSTRAINT {old_name} TO {new_name}")
777            }
778            AlterTableOperation::SwapWith { table_name } => {
779                write!(f, "SWAP WITH {table_name}")
780            }
781            AlterTableOperation::OwnerTo { new_owner } => {
782                write!(f, "OWNER TO {new_owner}")
783            }
784            AlterTableOperation::SetTblProperties { table_properties } => {
785                write!(
786                    f,
787                    "SET TBLPROPERTIES({})",
788                    display_comma_separated(table_properties)
789                )
790            }
791            AlterTableOperation::FreezePartition {
792                partition,
793                with_name,
794            } => {
795                write!(f, "FREEZE {partition}")?;
796                if let Some(name) = with_name {
797                    write!(f, " WITH NAME {name}")?;
798                }
799                Ok(())
800            }
801            AlterTableOperation::UnfreezePartition {
802                partition,
803                with_name,
804            } => {
805                write!(f, "UNFREEZE {partition}")?;
806                if let Some(name) = with_name {
807                    write!(f, " WITH NAME {name}")?;
808                }
809                Ok(())
810            }
811            AlterTableOperation::ClusterBy { exprs } => {
812                write!(f, "CLUSTER BY ({})", display_comma_separated(exprs))?;
813                Ok(())
814            }
815            AlterTableOperation::DropClusteringKey => {
816                write!(f, "DROP CLUSTERING KEY")?;
817                Ok(())
818            }
819            AlterTableOperation::SuspendRecluster => {
820                write!(f, "SUSPEND RECLUSTER")?;
821                Ok(())
822            }
823            AlterTableOperation::ResumeRecluster => {
824                write!(f, "RESUME RECLUSTER")?;
825                Ok(())
826            }
827            AlterTableOperation::AutoIncrement { equals, value } => {
828                write!(
829                    f,
830                    "AUTO_INCREMENT {}{}",
831                    if *equals { "= " } else { "" },
832                    value
833                )
834            }
835            AlterTableOperation::Lock { equals, lock } => {
836                write!(f, "LOCK {}{}", if *equals { "= " } else { "" }, lock)
837            }
838            AlterTableOperation::ReplicaIdentity { identity } => {
839                write!(f, "REPLICA IDENTITY {identity}")
840            }
841            AlterTableOperation::ValidateConstraint { name } => {
842                write!(f, "VALIDATE CONSTRAINT {name}")
843            }
844            AlterTableOperation::SetOptionsParens { options } => {
845                write!(f, "SET ({})", display_comma_separated(options))
846            }
847        }
848    }
849}
850
851impl fmt::Display for AlterIndexOperation {
852    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
853        match self {
854            AlterIndexOperation::RenameIndex { index_name } => {
855                write!(f, "RENAME TO {index_name}")
856            }
857        }
858    }
859}
860
861/// An `ALTER TYPE` statement (`Statement::AlterType`)
862#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
863#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
864#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
865pub struct AlterType {
866    pub name: ObjectName,
867    pub operation: AlterTypeOperation,
868}
869
870/// An [AlterType] operation
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 AlterTypeOperation {
875    Rename(AlterTypeRename),
876    AddValue(AlterTypeAddValue),
877    RenameValue(AlterTypeRenameValue),
878}
879
880/// See [AlterTypeOperation::Rename]
881#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
882#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
883#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
884pub struct AlterTypeRename {
885    pub new_name: Ident,
886}
887
888/// See [AlterTypeOperation::AddValue]
889#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
890#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
891#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
892pub struct AlterTypeAddValue {
893    pub if_not_exists: bool,
894    pub value: Ident,
895    pub position: Option<AlterTypeAddValuePosition>,
896}
897
898/// See [AlterTypeAddValue]
899#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
900#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
901#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
902pub enum AlterTypeAddValuePosition {
903    Before(Ident),
904    After(Ident),
905}
906
907/// See [AlterTypeOperation::RenameValue]
908#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
909#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
910#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
911pub struct AlterTypeRenameValue {
912    pub from: Ident,
913    pub to: Ident,
914}
915
916impl fmt::Display for AlterTypeOperation {
917    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
918        match self {
919            Self::Rename(AlterTypeRename { new_name }) => {
920                write!(f, "RENAME TO {new_name}")
921            }
922            Self::AddValue(AlterTypeAddValue {
923                if_not_exists,
924                value,
925                position,
926            }) => {
927                write!(f, "ADD VALUE")?;
928                if *if_not_exists {
929                    write!(f, " IF NOT EXISTS")?;
930                }
931                write!(f, " {value}")?;
932                match position {
933                    Some(AlterTypeAddValuePosition::Before(neighbor_value)) => {
934                        write!(f, " BEFORE {neighbor_value}")?;
935                    }
936                    Some(AlterTypeAddValuePosition::After(neighbor_value)) => {
937                        write!(f, " AFTER {neighbor_value}")?;
938                    }
939                    None => {}
940                };
941                Ok(())
942            }
943            Self::RenameValue(AlterTypeRenameValue { from, to }) => {
944                write!(f, "RENAME VALUE {from} TO {to}")
945            }
946        }
947    }
948}
949
950/// An `ALTER COLUMN` (`Statement::AlterTable`) operation
951#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
952#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
953#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
954pub enum AlterColumnOperation {
955    /// `SET NOT NULL`
956    SetNotNull,
957    /// `DROP NOT NULL`
958    DropNotNull,
959    /// `SET DEFAULT <expr>`
960    SetDefault { value: Expr },
961    /// `DROP DEFAULT`
962    DropDefault,
963    /// `[SET DATA] TYPE <data_type> [USING <expr>]`
964    SetDataType {
965        data_type: DataType,
966        /// PostgreSQL specific
967        using: Option<Expr>,
968        /// Set to true if the statement includes the `SET DATA TYPE` keywords
969        had_set: bool,
970    },
971
972    /// `ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]`
973    ///
974    /// Note: this is a PostgreSQL-specific operation.
975    AddGenerated {
976        generated_as: Option<GeneratedAs>,
977        sequence_options: Option<Vec<SequenceOptions>>,
978    },
979}
980
981impl fmt::Display for AlterColumnOperation {
982    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
983        match self {
984            AlterColumnOperation::SetNotNull => write!(f, "SET NOT NULL",),
985            AlterColumnOperation::DropNotNull => write!(f, "DROP NOT NULL",),
986            AlterColumnOperation::SetDefault { value } => {
987                write!(f, "SET DEFAULT {value}")
988            }
989            AlterColumnOperation::DropDefault => {
990                write!(f, "DROP DEFAULT")
991            }
992            AlterColumnOperation::SetDataType {
993                data_type,
994                using,
995                had_set,
996            } => {
997                if *had_set {
998                    write!(f, "SET DATA ")?;
999                }
1000                write!(f, "TYPE {data_type}")?;
1001                if let Some(expr) = using {
1002                    write!(f, " USING {expr}")?;
1003                }
1004                Ok(())
1005            }
1006            AlterColumnOperation::AddGenerated {
1007                generated_as,
1008                sequence_options,
1009            } => {
1010                let generated_as = match generated_as {
1011                    Some(GeneratedAs::Always) => " ALWAYS",
1012                    Some(GeneratedAs::ByDefault) => " BY DEFAULT",
1013                    _ => "",
1014                };
1015
1016                write!(f, "ADD GENERATED{generated_as} AS IDENTITY",)?;
1017                if let Some(options) = sequence_options {
1018                    write!(f, " (")?;
1019
1020                    for sequence_option in options {
1021                        write!(f, "{sequence_option}")?;
1022                    }
1023
1024                    write!(f, " )")?;
1025                }
1026                Ok(())
1027            }
1028        }
1029    }
1030}
1031
1032/// A table-level constraint, specified in a `CREATE TABLE` or an
1033/// `ALTER TABLE ADD <constraint>` statement.
1034#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1035#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1036#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1037pub enum TableConstraint {
1038    /// MySQL [definition][1] for `UNIQUE` constraints statements:\
1039    /// * `[CONSTRAINT [<name>]] UNIQUE <index_type_display> [<index_name>] [index_type] (<columns>) <index_options>`
1040    ///
1041    /// where:
1042    /// * [index_type][2] is `USING {BTREE | HASH}`
1043    /// * [index_options][3] is `{index_type | COMMENT 'string' | ... %currently unsupported stmts% } ...`
1044    /// * [index_type_display][4] is `[INDEX | KEY]`
1045    ///
1046    /// [1]: https://dev.mysql.com/doc/refman/8.3/en/create-table.html
1047    /// [2]: IndexType
1048    /// [3]: IndexOption
1049    /// [4]: KeyOrIndexDisplay
1050    Unique {
1051        /// Constraint name.
1052        ///
1053        /// Can be not the same as `index_name`
1054        name: Option<Ident>,
1055        /// Index name
1056        index_name: Option<Ident>,
1057        /// Whether the type is followed by the keyword `KEY`, `INDEX`, or no keyword at all.
1058        index_type_display: KeyOrIndexDisplay,
1059        /// Optional `USING` of [index type][1] statement before columns.
1060        ///
1061        /// [1]: IndexType
1062        index_type: Option<IndexType>,
1063        /// Identifiers of the columns that are unique.
1064        columns: Vec<IndexColumn>,
1065        index_options: Vec<IndexOption>,
1066        characteristics: Option<ConstraintCharacteristics>,
1067        /// Optional Postgres nulls handling: `[ NULLS [ NOT ] DISTINCT ]`
1068        nulls_distinct: NullsDistinctOption,
1069    },
1070    /// MySQL [definition][1] for `PRIMARY KEY` constraints statements:\
1071    /// * `[CONSTRAINT [<name>]] PRIMARY KEY [index_name] [index_type] (<columns>) <index_options>`
1072    ///
1073    /// Actually the specification have no `[index_name]` but the next query will complete successfully:
1074    /// ```sql
1075    /// CREATE TABLE unspec_table (
1076    ///   xid INT NOT NULL,
1077    ///   CONSTRAINT p_name PRIMARY KEY index_name USING BTREE (xid)
1078    /// );
1079    /// ```
1080    ///
1081    /// where:
1082    /// * [index_type][2] is `USING {BTREE | HASH}`
1083    /// * [index_options][3] is `{index_type | COMMENT 'string' | ... %currently unsupported stmts% } ...`
1084    ///
1085    /// [1]: https://dev.mysql.com/doc/refman/8.3/en/create-table.html
1086    /// [2]: IndexType
1087    /// [3]: IndexOption
1088    PrimaryKey {
1089        /// Constraint name.
1090        ///
1091        /// Can be not the same as `index_name`
1092        name: Option<Ident>,
1093        /// Index name
1094        index_name: Option<Ident>,
1095        /// Optional `USING` of [index type][1] statement before columns.
1096        ///
1097        /// [1]: IndexType
1098        index_type: Option<IndexType>,
1099        /// Identifiers of the columns that form the primary key.
1100        columns: Vec<IndexColumn>,
1101        index_options: Vec<IndexOption>,
1102        characteristics: Option<ConstraintCharacteristics>,
1103    },
1104    /// A referential integrity constraint (`[ CONSTRAINT <name> ] FOREIGN KEY (<columns>)
1105    /// REFERENCES <foreign_table> (<referred_columns>)
1106    /// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
1107    ///   [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
1108    /// }`).
1109    ForeignKey {
1110        name: Option<Ident>,
1111        /// MySQL-specific field
1112        /// <https://dev.mysql.com/doc/refman/8.4/en/create-table-foreign-keys.html>
1113        index_name: Option<Ident>,
1114        columns: Vec<Ident>,
1115        foreign_table: ObjectName,
1116        referred_columns: Vec<Ident>,
1117        on_delete: Option<ReferentialAction>,
1118        on_update: Option<ReferentialAction>,
1119        characteristics: Option<ConstraintCharacteristics>,
1120    },
1121    /// `[ CONSTRAINT <name> ] CHECK (<expr>) [[NOT] ENFORCED]`
1122    Check {
1123        name: Option<Ident>,
1124        expr: Box<Expr>,
1125        /// MySQL-specific syntax
1126        /// <https://dev.mysql.com/doc/refman/8.4/en/create-table.html>
1127        enforced: Option<bool>,
1128    },
1129    /// MySQLs [index definition][1] for index creation. Not present on ANSI so, for now, the usage
1130    /// is restricted to MySQL, as no other dialects that support this syntax were found.
1131    ///
1132    /// `{INDEX | KEY} [index_name] [index_type] (key_part,...) [index_option]...`
1133    ///
1134    /// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1135    Index {
1136        /// Whether this index starts with KEY (true) or INDEX (false), to maintain the same syntax.
1137        display_as_key: bool,
1138        /// Index name.
1139        name: Option<Ident>,
1140        /// Optional [index type][1].
1141        ///
1142        /// [1]: IndexType
1143        index_type: Option<IndexType>,
1144        /// Referred column identifier list.
1145        columns: Vec<IndexColumn>,
1146        /// Optional index options such as `USING`; see [`IndexOption`].
1147        index_options: Vec<IndexOption>,
1148    },
1149    /// MySQLs [fulltext][1] definition. Since the [`SPATIAL`][2] definition is exactly the same,
1150    /// and MySQL displays both the same way, it is part of this definition as well.
1151    ///
1152    /// Supported syntax:
1153    ///
1154    /// ```markdown
1155    /// {FULLTEXT | SPATIAL} [INDEX | KEY] [index_name] (key_part,...)
1156    ///
1157    /// key_part: col_name
1158    /// ```
1159    ///
1160    /// [1]: https://dev.mysql.com/doc/refman/8.0/en/fulltext-natural-language.html
1161    /// [2]: https://dev.mysql.com/doc/refman/8.0/en/spatial-types.html
1162    FulltextOrSpatial {
1163        /// Whether this is a `FULLTEXT` (true) or `SPATIAL` (false) definition.
1164        fulltext: bool,
1165        /// Whether the type is followed by the keyword `KEY`, `INDEX`, or no keyword at all.
1166        index_type_display: KeyOrIndexDisplay,
1167        /// Optional index name.
1168        opt_index_name: Option<Ident>,
1169        /// Referred column identifier list.
1170        columns: Vec<IndexColumn>,
1171    },
1172}
1173
1174impl fmt::Display for TableConstraint {
1175    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1176        match self {
1177            TableConstraint::Unique {
1178                name,
1179                index_name,
1180                index_type_display,
1181                index_type,
1182                columns,
1183                index_options,
1184                characteristics,
1185                nulls_distinct,
1186            } => {
1187                write!(
1188                    f,
1189                    "{}UNIQUE{nulls_distinct}{index_type_display:>}{}{} ({})",
1190                    display_constraint_name(name),
1191                    display_option_spaced(index_name),
1192                    display_option(" USING ", "", index_type),
1193                    display_comma_separated(columns),
1194                )?;
1195
1196                if !index_options.is_empty() {
1197                    write!(f, " {}", display_separated(index_options, " "))?;
1198                }
1199
1200                write!(f, "{}", display_option_spaced(characteristics))?;
1201                Ok(())
1202            }
1203            TableConstraint::PrimaryKey {
1204                name,
1205                index_name,
1206                index_type,
1207                columns,
1208                index_options,
1209                characteristics,
1210            } => {
1211                write!(
1212                    f,
1213                    "{}PRIMARY KEY{}{} ({})",
1214                    display_constraint_name(name),
1215                    display_option_spaced(index_name),
1216                    display_option(" USING ", "", index_type),
1217                    display_comma_separated(columns),
1218                )?;
1219
1220                if !index_options.is_empty() {
1221                    write!(f, " {}", display_separated(index_options, " "))?;
1222                }
1223
1224                write!(f, "{}", display_option_spaced(characteristics))?;
1225                Ok(())
1226            }
1227            TableConstraint::ForeignKey {
1228                name,
1229                index_name,
1230                columns,
1231                foreign_table,
1232                referred_columns,
1233                on_delete,
1234                on_update,
1235                characteristics,
1236            } => {
1237                write!(
1238                    f,
1239                    "{}FOREIGN KEY{} ({}) REFERENCES {}",
1240                    display_constraint_name(name),
1241                    display_option_spaced(index_name),
1242                    display_comma_separated(columns),
1243                    foreign_table,
1244                )?;
1245                if !referred_columns.is_empty() {
1246                    write!(f, "({})", display_comma_separated(referred_columns))?;
1247                }
1248                if let Some(action) = on_delete {
1249                    write!(f, " ON DELETE {action}")?;
1250                }
1251                if let Some(action) = on_update {
1252                    write!(f, " ON UPDATE {action}")?;
1253                }
1254                if let Some(characteristics) = characteristics {
1255                    write!(f, " {characteristics}")?;
1256                }
1257                Ok(())
1258            }
1259            TableConstraint::Check {
1260                name,
1261                expr,
1262                enforced,
1263            } => {
1264                write!(f, "{}CHECK ({})", display_constraint_name(name), expr)?;
1265                if let Some(b) = enforced {
1266                    write!(f, " {}", if *b { "ENFORCED" } else { "NOT ENFORCED" })
1267                } else {
1268                    Ok(())
1269                }
1270            }
1271            TableConstraint::Index {
1272                display_as_key,
1273                name,
1274                index_type,
1275                columns,
1276                index_options,
1277            } => {
1278                write!(f, "{}", if *display_as_key { "KEY" } else { "INDEX" })?;
1279                if let Some(name) = name {
1280                    write!(f, " {name}")?;
1281                }
1282                if let Some(index_type) = index_type {
1283                    write!(f, " USING {index_type}")?;
1284                }
1285                write!(f, " ({})", display_comma_separated(columns))?;
1286                if !index_options.is_empty() {
1287                    write!(f, " {}", display_comma_separated(index_options))?;
1288                }
1289                Ok(())
1290            }
1291            Self::FulltextOrSpatial {
1292                fulltext,
1293                index_type_display,
1294                opt_index_name,
1295                columns,
1296            } => {
1297                if *fulltext {
1298                    write!(f, "FULLTEXT")?;
1299                } else {
1300                    write!(f, "SPATIAL")?;
1301                }
1302
1303                write!(f, "{index_type_display:>}")?;
1304
1305                if let Some(name) = opt_index_name {
1306                    write!(f, " {name}")?;
1307                }
1308
1309                write!(f, " ({})", display_comma_separated(columns))?;
1310
1311                Ok(())
1312            }
1313        }
1314    }
1315}
1316
1317/// Representation whether a definition can can contains the KEY or INDEX keywords with the same
1318/// meaning.
1319///
1320/// This enum initially is directed to `FULLTEXT`,`SPATIAL`, and `UNIQUE` indexes on create table
1321/// statements of `MySQL` [(1)].
1322///
1323/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1324#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1325#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1326#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1327pub enum KeyOrIndexDisplay {
1328    /// Nothing to display
1329    None,
1330    /// Display the KEY keyword
1331    Key,
1332    /// Display the INDEX keyword
1333    Index,
1334}
1335
1336impl KeyOrIndexDisplay {
1337    pub fn is_none(self) -> bool {
1338        matches!(self, Self::None)
1339    }
1340}
1341
1342impl fmt::Display for KeyOrIndexDisplay {
1343    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1344        let left_space = matches!(f.align(), Some(fmt::Alignment::Right));
1345
1346        if left_space && !self.is_none() {
1347            f.write_char(' ')?
1348        }
1349
1350        match self {
1351            KeyOrIndexDisplay::None => {
1352                write!(f, "")
1353            }
1354            KeyOrIndexDisplay::Key => {
1355                write!(f, "KEY")
1356            }
1357            KeyOrIndexDisplay::Index => {
1358                write!(f, "INDEX")
1359            }
1360        }
1361    }
1362}
1363
1364/// Indexing method used by that index.
1365///
1366/// This structure isn't present on ANSI, but is found at least in [`MySQL` CREATE TABLE][1],
1367/// [`MySQL` CREATE INDEX][2], and [Postgresql CREATE INDEX][3] statements.
1368///
1369/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1370/// [2]: https://dev.mysql.com/doc/refman/8.0/en/create-index.html
1371/// [3]: https://www.postgresql.org/docs/14/sql-createindex.html
1372#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1373#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1374#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1375pub enum IndexType {
1376    BTree,
1377    Hash,
1378    GIN,
1379    GiST,
1380    SPGiST,
1381    BRIN,
1382    Bloom,
1383    /// Users may define their own index types, which would
1384    /// not be covered by the above variants.
1385    Custom(Ident),
1386}
1387
1388impl fmt::Display for IndexType {
1389    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1390        match self {
1391            Self::BTree => write!(f, "BTREE"),
1392            Self::Hash => write!(f, "HASH"),
1393            Self::GIN => write!(f, "GIN"),
1394            Self::GiST => write!(f, "GIST"),
1395            Self::SPGiST => write!(f, "SPGIST"),
1396            Self::BRIN => write!(f, "BRIN"),
1397            Self::Bloom => write!(f, "BLOOM"),
1398            Self::Custom(name) => write!(f, "{name}"),
1399        }
1400    }
1401}
1402
1403/// MySQL index option, used in [`CREATE TABLE`], [`CREATE INDEX`], and [`ALTER TABLE`].
1404///
1405/// [`CREATE TABLE`]: https://dev.mysql.com/doc/refman/8.4/en/create-table.html
1406/// [`CREATE INDEX`]: https://dev.mysql.com/doc/refman/8.4/en/create-index.html
1407/// [`ALTER TABLE`]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
1408#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1409#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1410#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1411pub enum IndexOption {
1412    /// `USING { BTREE | HASH }`: Index type to use for the index.
1413    ///
1414    /// Note that we permissively parse non-MySQL index types, like `GIN`.
1415    Using(IndexType),
1416    /// `COMMENT 'string'`: Specifies a comment for the index.
1417    Comment(String),
1418}
1419
1420impl fmt::Display for IndexOption {
1421    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1422        match self {
1423            Self::Using(index_type) => write!(f, "USING {index_type}"),
1424            Self::Comment(s) => write!(f, "COMMENT '{s}'"),
1425        }
1426    }
1427}
1428
1429/// [PostgreSQL] unique index nulls handling option: `[ NULLS [ NOT ] DISTINCT ]`
1430///
1431/// [PostgreSQL]: https://www.postgresql.org/docs/17/sql-altertable.html
1432#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1433#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1434#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1435pub enum NullsDistinctOption {
1436    /// Not specified
1437    None,
1438    /// NULLS DISTINCT
1439    Distinct,
1440    /// NULLS NOT DISTINCT
1441    NotDistinct,
1442}
1443
1444impl fmt::Display for NullsDistinctOption {
1445    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1446        match self {
1447            Self::None => Ok(()),
1448            Self::Distinct => write!(f, " NULLS DISTINCT"),
1449            Self::NotDistinct => write!(f, " NULLS NOT DISTINCT"),
1450        }
1451    }
1452}
1453
1454#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1455#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1456#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1457pub struct ProcedureParam {
1458    pub name: Ident,
1459    pub data_type: DataType,
1460    pub mode: Option<ArgMode>,
1461}
1462
1463impl fmt::Display for ProcedureParam {
1464    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1465        if let Some(mode) = &self.mode {
1466            write!(f, "{mode} {} {}", self.name, self.data_type)
1467        } else {
1468            write!(f, "{} {}", self.name, self.data_type)
1469        }
1470    }
1471}
1472
1473/// SQL column definition
1474#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1475#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1476#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1477pub struct ColumnDef {
1478    pub name: Ident,
1479    pub data_type: DataType,
1480    pub options: Vec<ColumnOptionDef>,
1481}
1482
1483impl fmt::Display for ColumnDef {
1484    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1485        if self.data_type == DataType::Unspecified {
1486            write!(f, "{}", self.name)?;
1487        } else {
1488            write!(f, "{} {}", self.name, self.data_type)?;
1489        }
1490        for option in &self.options {
1491            write!(f, " {option}")?;
1492        }
1493        Ok(())
1494    }
1495}
1496
1497/// Column definition specified in a `CREATE VIEW` statement.
1498///
1499/// Syntax
1500/// ```markdown
1501/// <name> [data_type][OPTIONS(option, ...)]
1502///
1503/// option: <name> = <value>
1504/// ```
1505///
1506/// Examples:
1507/// ```sql
1508/// name
1509/// age OPTIONS(description = "age column", tag = "prod")
1510/// amount COMMENT 'The total amount for the order line'
1511/// created_at DateTime64
1512/// ```
1513#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1514#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1515#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1516pub struct ViewColumnDef {
1517    pub name: Ident,
1518    pub data_type: Option<DataType>,
1519    pub options: Option<ColumnOptions>,
1520}
1521
1522#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1523#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1524#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1525pub enum ColumnOptions {
1526    CommaSeparated(Vec<ColumnOption>),
1527    SpaceSeparated(Vec<ColumnOption>),
1528}
1529
1530impl ColumnOptions {
1531    pub fn as_slice(&self) -> &[ColumnOption] {
1532        match self {
1533            ColumnOptions::CommaSeparated(options) => options.as_slice(),
1534            ColumnOptions::SpaceSeparated(options) => options.as_slice(),
1535        }
1536    }
1537}
1538
1539impl fmt::Display for ViewColumnDef {
1540    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1541        write!(f, "{}", self.name)?;
1542        if let Some(data_type) = self.data_type.as_ref() {
1543            write!(f, " {data_type}")?;
1544        }
1545        if let Some(options) = self.options.as_ref() {
1546            match options {
1547                ColumnOptions::CommaSeparated(column_options) => {
1548                    write!(f, " {}", display_comma_separated(column_options.as_slice()))?;
1549                }
1550                ColumnOptions::SpaceSeparated(column_options) => {
1551                    write!(f, " {}", display_separated(column_options.as_slice(), " "))?
1552                }
1553            }
1554        }
1555        Ok(())
1556    }
1557}
1558
1559/// An optionally-named `ColumnOption`: `[ CONSTRAINT <name> ] <column-option>`.
1560///
1561/// Note that implementations are substantially more permissive than the ANSI
1562/// specification on what order column options can be presented in, and whether
1563/// they are allowed to be named. The specification distinguishes between
1564/// constraints (NOT NULL, UNIQUE, PRIMARY KEY, and CHECK), which can be named
1565/// and can appear in any order, and other options (DEFAULT, GENERATED), which
1566/// cannot be named and must appear in a fixed order. `PostgreSQL`, however,
1567/// allows preceding any option with `CONSTRAINT <name>`, even those that are
1568/// not really constraints, like NULL and DEFAULT. MSSQL is less permissive,
1569/// allowing DEFAULT, UNIQUE, PRIMARY KEY and CHECK to be named, but not NULL or
1570/// NOT NULL constraints (the last of which is in violation of the spec).
1571///
1572/// For maximum flexibility, we don't distinguish between constraint and
1573/// non-constraint options, lumping them all together under the umbrella of
1574/// "column options," and we allow any column option to be named.
1575#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1576#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1577#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1578pub struct ColumnOptionDef {
1579    pub name: Option<Ident>,
1580    pub option: ColumnOption,
1581}
1582
1583impl fmt::Display for ColumnOptionDef {
1584    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1585        write!(f, "{}{}", display_constraint_name(&self.name), self.option)
1586    }
1587}
1588
1589/// Identity is a column option for defining an identity or autoincrement column in a `CREATE TABLE` statement.
1590/// Syntax
1591/// ```sql
1592/// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1593/// ```
1594/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1595/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1596#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1597#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1598#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1599pub enum IdentityPropertyKind {
1600    /// An identity property declared via the `AUTOINCREMENT` key word
1601    /// Example:
1602    /// ```sql
1603    ///  AUTOINCREMENT(100, 1) NOORDER
1604    ///  AUTOINCREMENT START 100 INCREMENT 1 ORDER
1605    /// ```
1606    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1607    Autoincrement(IdentityProperty),
1608    /// An identity property declared via the `IDENTITY` key word
1609    /// Example, [MS SQL Server] or [Snowflake]:
1610    /// ```sql
1611    ///  IDENTITY(100, 1)
1612    /// ```
1613    /// [Snowflake]
1614    /// ```sql
1615    ///  IDENTITY(100, 1) ORDER
1616    ///  IDENTITY START 100 INCREMENT 1 NOORDER
1617    /// ```
1618    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1619    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1620    Identity(IdentityProperty),
1621}
1622
1623impl fmt::Display for IdentityPropertyKind {
1624    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1625        let (command, property) = match self {
1626            IdentityPropertyKind::Identity(property) => ("IDENTITY", property),
1627            IdentityPropertyKind::Autoincrement(property) => ("AUTOINCREMENT", property),
1628        };
1629        write!(f, "{command}")?;
1630        if let Some(parameters) = &property.parameters {
1631            write!(f, "{parameters}")?;
1632        }
1633        if let Some(order) = &property.order {
1634            write!(f, "{order}")?;
1635        }
1636        Ok(())
1637    }
1638}
1639
1640#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1641#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1642#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1643pub struct IdentityProperty {
1644    pub parameters: Option<IdentityPropertyFormatKind>,
1645    pub order: Option<IdentityPropertyOrder>,
1646}
1647
1648/// A format of parameters of identity column.
1649///
1650/// It is [Snowflake] specific.
1651/// Syntax
1652/// ```sql
1653/// (seed , increment) | START num INCREMENT num
1654/// ```
1655/// [MS SQL Server] uses one way of representing these parameters.
1656/// Syntax
1657/// ```sql
1658/// (seed , increment)
1659/// ```
1660/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1661/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1662#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1663#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1664#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1665pub enum IdentityPropertyFormatKind {
1666    /// A parameters of identity column declared like parameters of function call
1667    /// Example:
1668    /// ```sql
1669    ///  (100, 1)
1670    /// ```
1671    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1672    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1673    FunctionCall(IdentityParameters),
1674    /// A parameters of identity column declared with keywords `START` and `INCREMENT`
1675    /// Example:
1676    /// ```sql
1677    ///  START 100 INCREMENT 1
1678    /// ```
1679    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1680    StartAndIncrement(IdentityParameters),
1681}
1682
1683impl fmt::Display for IdentityPropertyFormatKind {
1684    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1685        match self {
1686            IdentityPropertyFormatKind::FunctionCall(parameters) => {
1687                write!(f, "({}, {})", parameters.seed, parameters.increment)
1688            }
1689            IdentityPropertyFormatKind::StartAndIncrement(parameters) => {
1690                write!(
1691                    f,
1692                    " START {} INCREMENT {}",
1693                    parameters.seed, parameters.increment
1694                )
1695            }
1696        }
1697    }
1698}
1699#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1700#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1701#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1702pub struct IdentityParameters {
1703    pub seed: Expr,
1704    pub increment: Expr,
1705}
1706
1707/// The identity column option specifies how values are generated for the auto-incremented column, either in increasing or decreasing order.
1708/// Syntax
1709/// ```sql
1710/// ORDER | NOORDER
1711/// ```
1712/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1713#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1714#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1715#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1716pub enum IdentityPropertyOrder {
1717    Order,
1718    NoOrder,
1719}
1720
1721impl fmt::Display for IdentityPropertyOrder {
1722    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1723        match self {
1724            IdentityPropertyOrder::Order => write!(f, " ORDER"),
1725            IdentityPropertyOrder::NoOrder => write!(f, " NOORDER"),
1726        }
1727    }
1728}
1729
1730/// Column policy that identify a security policy of access to a column.
1731/// Syntax
1732/// ```sql
1733/// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1734/// [ WITH ] PROJECTION POLICY <policy_name>
1735/// ```
1736/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1737#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1738#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1739#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1740pub enum ColumnPolicy {
1741    MaskingPolicy(ColumnPolicyProperty),
1742    ProjectionPolicy(ColumnPolicyProperty),
1743}
1744
1745impl fmt::Display for ColumnPolicy {
1746    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1747        let (command, property) = match self {
1748            ColumnPolicy::MaskingPolicy(property) => ("MASKING POLICY", property),
1749            ColumnPolicy::ProjectionPolicy(property) => ("PROJECTION POLICY", property),
1750        };
1751        if property.with {
1752            write!(f, "WITH ")?;
1753        }
1754        write!(f, "{command} {}", property.policy_name)?;
1755        if let Some(using_columns) = &property.using_columns {
1756            write!(f, " USING ({})", display_comma_separated(using_columns))?;
1757        }
1758        Ok(())
1759    }
1760}
1761
1762#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1763#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1764#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1765pub struct ColumnPolicyProperty {
1766    /// This flag indicates that the column policy option is declared using the `WITH` prefix.
1767    /// Example
1768    /// ```sql
1769    /// WITH PROJECTION POLICY sample_policy
1770    /// ```
1771    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1772    pub with: bool,
1773    pub policy_name: ObjectName,
1774    pub using_columns: Option<Vec<Ident>>,
1775}
1776
1777/// Tags option of column
1778/// Syntax
1779/// ```sql
1780/// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1781/// ```
1782/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1783#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1784#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1785#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1786pub struct TagsColumnOption {
1787    /// This flag indicates that the tags option is declared using the `WITH` prefix.
1788    /// Example:
1789    /// ```sql
1790    /// WITH TAG (A = 'Tag A')
1791    /// ```
1792    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1793    pub with: bool,
1794    pub tags: Vec<Tag>,
1795}
1796
1797impl fmt::Display for TagsColumnOption {
1798    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1799        if self.with {
1800            write!(f, "WITH ")?;
1801        }
1802        write!(f, "TAG ({})", display_comma_separated(&self.tags))?;
1803        Ok(())
1804    }
1805}
1806
1807/// `ColumnOption`s are modifiers that follow a column definition in a `CREATE
1808/// TABLE` statement.
1809#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1810#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1811#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1812pub enum ColumnOption {
1813    /// `NULL`
1814    Null,
1815    /// `NOT NULL`
1816    NotNull,
1817    /// `DEFAULT <restricted-expr>`
1818    Default(Expr),
1819
1820    /// `MATERIALIZE <expr>`
1821    /// Syntax: `b INT MATERIALIZE (a + 1)`
1822    ///
1823    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1824    Materialized(Expr),
1825    /// `EPHEMERAL [<expr>]`
1826    ///
1827    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1828    Ephemeral(Option<Expr>),
1829    /// `ALIAS <expr>`
1830    ///
1831    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1832    Alias(Expr),
1833
1834    /// `{ PRIMARY KEY | UNIQUE } [<constraint_characteristics>]`
1835    Unique {
1836        is_primary: bool,
1837        characteristics: Option<ConstraintCharacteristics>,
1838    },
1839    /// A referential integrity constraint (`[FOREIGN KEY REFERENCES
1840    /// <foreign_table> (<referred_columns>)
1841    /// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
1842    ///   [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
1843    /// }
1844    /// [<constraint_characteristics>]
1845    /// `).
1846    ForeignKey {
1847        foreign_table: ObjectName,
1848        referred_columns: Vec<Ident>,
1849        on_delete: Option<ReferentialAction>,
1850        on_update: Option<ReferentialAction>,
1851        characteristics: Option<ConstraintCharacteristics>,
1852    },
1853    /// `CHECK (<expr>)`
1854    Check(Expr),
1855    /// Dialect-specific options, such as:
1856    /// - MySQL's `AUTO_INCREMENT` or SQLite's `AUTOINCREMENT`
1857    /// - ...
1858    DialectSpecific(Vec<Token>),
1859    CharacterSet(ObjectName),
1860    Collation(ObjectName),
1861    Comment(String),
1862    OnUpdate(Expr),
1863    /// `Generated`s are modifiers that follow a column definition in a `CREATE
1864    /// TABLE` statement.
1865    Generated {
1866        generated_as: GeneratedAs,
1867        sequence_options: Option<Vec<SequenceOptions>>,
1868        generation_expr: Option<Expr>,
1869        generation_expr_mode: Option<GeneratedExpressionMode>,
1870        /// false if 'GENERATED ALWAYS' is skipped (option starts with AS)
1871        generated_keyword: bool,
1872    },
1873    /// BigQuery specific: Explicit column options in a view [1] or table [2]
1874    /// Syntax
1875    /// ```sql
1876    /// OPTIONS(description="field desc")
1877    /// ```
1878    /// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#view_column_option_list
1879    /// [2]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#column_option_list
1880    Options(Vec<SqlOption>),
1881    /// Creates an identity or an autoincrement column in a table.
1882    /// Syntax
1883    /// ```sql
1884    /// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1885    /// ```
1886    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1887    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1888    Identity(IdentityPropertyKind),
1889    /// SQLite specific: ON CONFLICT option on column definition
1890    /// <https://www.sqlite.org/lang_conflict.html>
1891    OnConflict(Keyword),
1892    /// Snowflake specific: an option of specifying security masking or projection policy to set on a column.
1893    /// Syntax:
1894    /// ```sql
1895    /// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1896    /// [ WITH ] PROJECTION POLICY <policy_name>
1897    /// ```
1898    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1899    Policy(ColumnPolicy),
1900    /// Snowflake specific: Specifies the tag name and the tag string value.
1901    /// Syntax:
1902    /// ```sql
1903    /// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1904    /// ```
1905    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1906    Tags(TagsColumnOption),
1907    /// MySQL specific: Spatial reference identifier
1908    /// Syntax:
1909    /// ```sql
1910    /// CREATE TABLE geom (g GEOMETRY NOT NULL SRID 4326);
1911    /// ```
1912    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/creating-spatial-indexes.html
1913    Srid(Box<Expr>),
1914}
1915
1916impl fmt::Display for ColumnOption {
1917    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1918        use ColumnOption::*;
1919        match self {
1920            Null => write!(f, "NULL"),
1921            NotNull => write!(f, "NOT NULL"),
1922            Default(expr) => write!(f, "DEFAULT {expr}"),
1923            Materialized(expr) => write!(f, "MATERIALIZED {expr}"),
1924            Ephemeral(expr) => {
1925                if let Some(e) = expr {
1926                    write!(f, "EPHEMERAL {e}")
1927                } else {
1928                    write!(f, "EPHEMERAL")
1929                }
1930            }
1931            Alias(expr) => write!(f, "ALIAS {expr}"),
1932            Unique {
1933                is_primary,
1934                characteristics,
1935            } => {
1936                write!(f, "{}", if *is_primary { "PRIMARY KEY" } else { "UNIQUE" })?;
1937                if let Some(characteristics) = characteristics {
1938                    write!(f, " {characteristics}")?;
1939                }
1940                Ok(())
1941            }
1942            ForeignKey {
1943                foreign_table,
1944                referred_columns,
1945                on_delete,
1946                on_update,
1947                characteristics,
1948            } => {
1949                write!(f, "REFERENCES {foreign_table}")?;
1950                if !referred_columns.is_empty() {
1951                    write!(f, " ({})", display_comma_separated(referred_columns))?;
1952                }
1953                if let Some(action) = on_delete {
1954                    write!(f, " ON DELETE {action}")?;
1955                }
1956                if let Some(action) = on_update {
1957                    write!(f, " ON UPDATE {action}")?;
1958                }
1959                if let Some(characteristics) = characteristics {
1960                    write!(f, " {characteristics}")?;
1961                }
1962                Ok(())
1963            }
1964            Check(expr) => write!(f, "CHECK ({expr})"),
1965            DialectSpecific(val) => write!(f, "{}", display_separated(val, " ")),
1966            CharacterSet(n) => write!(f, "CHARACTER SET {n}"),
1967            Collation(n) => write!(f, "COLLATE {n}"),
1968            Comment(v) => write!(f, "COMMENT '{}'", escape_single_quote_string(v)),
1969            OnUpdate(expr) => write!(f, "ON UPDATE {expr}"),
1970            Generated {
1971                generated_as,
1972                sequence_options,
1973                generation_expr,
1974                generation_expr_mode,
1975                generated_keyword,
1976            } => {
1977                if let Some(expr) = generation_expr {
1978                    let modifier = match generation_expr_mode {
1979                        None => "",
1980                        Some(GeneratedExpressionMode::Virtual) => " VIRTUAL",
1981                        Some(GeneratedExpressionMode::Stored) => " STORED",
1982                    };
1983                    if *generated_keyword {
1984                        write!(f, "GENERATED ALWAYS AS ({expr}){modifier}")?;
1985                    } else {
1986                        write!(f, "AS ({expr}){modifier}")?;
1987                    }
1988                    Ok(())
1989                } else {
1990                    // Like Postgres - generated from sequence
1991                    let when = match generated_as {
1992                        GeneratedAs::Always => "ALWAYS",
1993                        GeneratedAs::ByDefault => "BY DEFAULT",
1994                        // ExpStored goes with an expression, handled above
1995                        GeneratedAs::ExpStored => unreachable!(),
1996                    };
1997                    write!(f, "GENERATED {when} AS IDENTITY")?;
1998                    if sequence_options.is_some() {
1999                        let so = sequence_options.as_ref().unwrap();
2000                        if !so.is_empty() {
2001                            write!(f, " (")?;
2002                        }
2003                        for sequence_option in so {
2004                            write!(f, "{sequence_option}")?;
2005                        }
2006                        if !so.is_empty() {
2007                            write!(f, " )")?;
2008                        }
2009                    }
2010                    Ok(())
2011                }
2012            }
2013            Options(options) => {
2014                write!(f, "OPTIONS({})", display_comma_separated(options))
2015            }
2016            Identity(parameters) => {
2017                write!(f, "{parameters}")
2018            }
2019            OnConflict(keyword) => {
2020                write!(f, "ON CONFLICT {keyword:?}")?;
2021                Ok(())
2022            }
2023            Policy(parameters) => {
2024                write!(f, "{parameters}")
2025            }
2026            Tags(tags) => {
2027                write!(f, "{tags}")
2028            }
2029            Srid(srid) => {
2030                write!(f, "SRID {srid}")
2031            }
2032        }
2033    }
2034}
2035
2036/// `GeneratedAs`s are modifiers that follow a column option in a `generated`.
2037/// 'ExpStored' is used for a column generated from an expression and stored.
2038#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2039#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2040#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2041pub enum GeneratedAs {
2042    Always,
2043    ByDefault,
2044    ExpStored,
2045}
2046
2047/// `GeneratedExpressionMode`s are modifiers that follow an expression in a `generated`.
2048/// No modifier is typically the same as Virtual.
2049#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2050#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2051#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2052pub enum GeneratedExpressionMode {
2053    Virtual,
2054    Stored,
2055}
2056
2057#[must_use]
2058fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
2059    struct ConstraintName<'a>(&'a Option<Ident>);
2060    impl fmt::Display for ConstraintName<'_> {
2061        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2062            if let Some(name) = self.0 {
2063                write!(f, "CONSTRAINT {name} ")?;
2064            }
2065            Ok(())
2066        }
2067    }
2068    ConstraintName(name)
2069}
2070
2071/// If `option` is
2072/// * `Some(inner)` => create display struct for `"{prefix}{inner}{postfix}"`
2073/// * `_` => do nothing
2074#[must_use]
2075fn display_option<'a, T: fmt::Display>(
2076    prefix: &'a str,
2077    postfix: &'a str,
2078    option: &'a Option<T>,
2079) -> impl fmt::Display + 'a {
2080    struct OptionDisplay<'a, T>(&'a str, &'a str, &'a Option<T>);
2081    impl<T: fmt::Display> fmt::Display for OptionDisplay<'_, T> {
2082        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2083            if let Some(inner) = self.2 {
2084                let (prefix, postfix) = (self.0, self.1);
2085                write!(f, "{prefix}{inner}{postfix}")?;
2086            }
2087            Ok(())
2088        }
2089    }
2090    OptionDisplay(prefix, postfix, option)
2091}
2092
2093/// If `option` is
2094/// * `Some(inner)` => create display struct for `" {inner}"`
2095/// * `_` => do nothing
2096#[must_use]
2097fn display_option_spaced<T: fmt::Display>(option: &Option<T>) -> impl fmt::Display + '_ {
2098    display_option(" ", "", option)
2099}
2100
2101/// `<constraint_characteristics> = [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ]`
2102///
2103/// Used in UNIQUE and foreign key constraints. The individual settings may occur in any order.
2104#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Default, Eq, Ord, Hash)]
2105#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2106#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2107pub struct ConstraintCharacteristics {
2108    /// `[ DEFERRABLE | NOT DEFERRABLE ]`
2109    pub deferrable: Option<bool>,
2110    /// `[ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]`
2111    pub initially: Option<DeferrableInitial>,
2112    /// `[ ENFORCED | NOT ENFORCED ]`
2113    pub enforced: Option<bool>,
2114}
2115
2116#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2117#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2118#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2119pub enum DeferrableInitial {
2120    /// `INITIALLY IMMEDIATE`
2121    Immediate,
2122    /// `INITIALLY DEFERRED`
2123    Deferred,
2124}
2125
2126impl ConstraintCharacteristics {
2127    fn deferrable_text(&self) -> Option<&'static str> {
2128        self.deferrable.map(|deferrable| {
2129            if deferrable {
2130                "DEFERRABLE"
2131            } else {
2132                "NOT DEFERRABLE"
2133            }
2134        })
2135    }
2136
2137    fn initially_immediate_text(&self) -> Option<&'static str> {
2138        self.initially
2139            .map(|initially_immediate| match initially_immediate {
2140                DeferrableInitial::Immediate => "INITIALLY IMMEDIATE",
2141                DeferrableInitial::Deferred => "INITIALLY DEFERRED",
2142            })
2143    }
2144
2145    fn enforced_text(&self) -> Option<&'static str> {
2146        self.enforced.map(
2147            |enforced| {
2148                if enforced {
2149                    "ENFORCED"
2150                } else {
2151                    "NOT ENFORCED"
2152                }
2153            },
2154        )
2155    }
2156}
2157
2158impl fmt::Display for ConstraintCharacteristics {
2159    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2160        let deferrable = self.deferrable_text();
2161        let initially_immediate = self.initially_immediate_text();
2162        let enforced = self.enforced_text();
2163
2164        match (deferrable, initially_immediate, enforced) {
2165            (None, None, None) => Ok(()),
2166            (None, None, Some(enforced)) => write!(f, "{enforced}"),
2167            (None, Some(initial), None) => write!(f, "{initial}"),
2168            (None, Some(initial), Some(enforced)) => write!(f, "{initial} {enforced}"),
2169            (Some(deferrable), None, None) => write!(f, "{deferrable}"),
2170            (Some(deferrable), None, Some(enforced)) => write!(f, "{deferrable} {enforced}"),
2171            (Some(deferrable), Some(initial), None) => write!(f, "{deferrable} {initial}"),
2172            (Some(deferrable), Some(initial), Some(enforced)) => {
2173                write!(f, "{deferrable} {initial} {enforced}")
2174            }
2175        }
2176    }
2177}
2178
2179/// `<referential_action> =
2180/// { RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT }`
2181///
2182/// Used in foreign key constraints in `ON UPDATE` and `ON DELETE` options.
2183#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2184#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2185#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2186pub enum ReferentialAction {
2187    Restrict,
2188    Cascade,
2189    SetNull,
2190    NoAction,
2191    SetDefault,
2192}
2193
2194impl fmt::Display for ReferentialAction {
2195    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2196        f.write_str(match self {
2197            ReferentialAction::Restrict => "RESTRICT",
2198            ReferentialAction::Cascade => "CASCADE",
2199            ReferentialAction::SetNull => "SET NULL",
2200            ReferentialAction::NoAction => "NO ACTION",
2201            ReferentialAction::SetDefault => "SET DEFAULT",
2202        })
2203    }
2204}
2205
2206/// `<drop behavior> ::= CASCADE | RESTRICT`.
2207///
2208/// Used in `DROP` statements.
2209#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2210#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2211#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2212pub enum DropBehavior {
2213    Restrict,
2214    Cascade,
2215}
2216
2217impl fmt::Display for DropBehavior {
2218    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2219        f.write_str(match self {
2220            DropBehavior::Restrict => "RESTRICT",
2221            DropBehavior::Cascade => "CASCADE",
2222        })
2223    }
2224}
2225
2226/// SQL user defined type definition
2227#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2228#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2229#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2230pub enum UserDefinedTypeRepresentation {
2231    Composite {
2232        attributes: Vec<UserDefinedTypeCompositeAttributeDef>,
2233    },
2234    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2235    Enum { labels: Vec<Ident> },
2236}
2237
2238impl fmt::Display for UserDefinedTypeRepresentation {
2239    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2240        match self {
2241            UserDefinedTypeRepresentation::Composite { attributes } => {
2242                write!(f, "({})", display_comma_separated(attributes))
2243            }
2244            UserDefinedTypeRepresentation::Enum { labels } => {
2245                write!(f, "ENUM ({})", display_comma_separated(labels))
2246            }
2247        }
2248    }
2249}
2250
2251/// SQL user defined type attribute definition
2252#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2253#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2254#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2255pub struct UserDefinedTypeCompositeAttributeDef {
2256    pub name: Ident,
2257    pub data_type: DataType,
2258    pub collation: Option<ObjectName>,
2259}
2260
2261impl fmt::Display for UserDefinedTypeCompositeAttributeDef {
2262    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2263        write!(f, "{} {}", self.name, self.data_type)?;
2264        if let Some(collation) = &self.collation {
2265            write!(f, " COLLATE {collation}")?;
2266        }
2267        Ok(())
2268    }
2269}
2270
2271/// PARTITION statement used in ALTER TABLE et al. such as in Hive and ClickHouse SQL.
2272/// For example, ClickHouse's OPTIMIZE TABLE supports syntax like PARTITION ID 'partition_id' and PARTITION expr.
2273/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2274#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2275#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2276#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2277pub enum Partition {
2278    Identifier(Ident),
2279    Expr(Expr),
2280    /// ClickHouse supports PART expr which represents physical partition in disk.
2281    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
2282    Part(Expr),
2283    Partitions(Vec<Expr>),
2284}
2285
2286impl fmt::Display for Partition {
2287    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2288        match self {
2289            Partition::Identifier(id) => write!(f, "PARTITION ID {id}"),
2290            Partition::Expr(expr) => write!(f, "PARTITION {expr}"),
2291            Partition::Part(expr) => write!(f, "PART {expr}"),
2292            Partition::Partitions(partitions) => {
2293                write!(f, "PARTITION ({})", display_comma_separated(partitions))
2294            }
2295        }
2296    }
2297}
2298
2299/// DEDUPLICATE statement used in OPTIMIZE TABLE et al. such as in ClickHouse SQL
2300/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2301#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2302#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2303#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2304pub enum Deduplicate {
2305    All,
2306    ByExpression(Expr),
2307}
2308
2309impl fmt::Display for Deduplicate {
2310    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2311        match self {
2312            Deduplicate::All => write!(f, "DEDUPLICATE"),
2313            Deduplicate::ByExpression(expr) => write!(f, "DEDUPLICATE BY {expr}"),
2314        }
2315    }
2316}
2317
2318/// Hive supports `CLUSTERED BY` statement in `CREATE TABLE`.
2319/// Syntax: `CLUSTERED BY (col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS`
2320///
2321/// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2322#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2323#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2324#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2325pub struct ClusteredBy {
2326    pub columns: Vec<Ident>,
2327    pub sorted_by: Option<Vec<OrderByExpr>>,
2328    pub num_buckets: Value,
2329}
2330
2331impl fmt::Display for ClusteredBy {
2332    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2333        write!(
2334            f,
2335            "CLUSTERED BY ({})",
2336            display_comma_separated(&self.columns)
2337        )?;
2338        if let Some(ref sorted_by) = self.sorted_by {
2339            write!(f, " SORTED BY ({})", display_comma_separated(sorted_by))?;
2340        }
2341        write!(f, " INTO {} BUCKETS", self.num_buckets)
2342    }
2343}
2344
2345/// CREATE INDEX statement.
2346#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2347#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2348#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2349pub struct CreateIndex {
2350    /// index name
2351    pub name: Option<ObjectName>,
2352    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2353    pub table_name: ObjectName,
2354    pub using: Option<IndexType>,
2355    pub columns: Vec<IndexColumn>,
2356    pub unique: bool,
2357    pub concurrently: bool,
2358    pub if_not_exists: bool,
2359    pub include: Vec<Ident>,
2360    pub nulls_distinct: Option<bool>,
2361    /// WITH clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2362    pub with: Vec<Expr>,
2363    pub predicate: Option<Expr>,
2364    pub index_options: Vec<IndexOption>,
2365    /// [MySQL] allows a subset of options normally used for `ALTER TABLE`:
2366    ///
2367    /// - `ALGORITHM`
2368    /// - `LOCK`
2369    ///
2370    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/create-index.html
2371    pub alter_options: Vec<AlterTableOperation>,
2372}
2373
2374impl fmt::Display for CreateIndex {
2375    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2376        write!(
2377            f,
2378            "CREATE {unique}INDEX {concurrently}{if_not_exists}",
2379            unique = if self.unique { "UNIQUE " } else { "" },
2380            concurrently = if self.concurrently {
2381                "CONCURRENTLY "
2382            } else {
2383                ""
2384            },
2385            if_not_exists = if self.if_not_exists {
2386                "IF NOT EXISTS "
2387            } else {
2388                ""
2389            },
2390        )?;
2391        if let Some(value) = &self.name {
2392            write!(f, "{value} ")?;
2393        }
2394        write!(f, "ON {}", self.table_name)?;
2395        if let Some(value) = &self.using {
2396            write!(f, " USING {value} ")?;
2397        }
2398        write!(f, "({})", display_comma_separated(&self.columns))?;
2399        if !self.include.is_empty() {
2400            write!(f, " INCLUDE ({})", display_comma_separated(&self.include))?;
2401        }
2402        if let Some(value) = self.nulls_distinct {
2403            if value {
2404                write!(f, " NULLS DISTINCT")?;
2405            } else {
2406                write!(f, " NULLS NOT DISTINCT")?;
2407            }
2408        }
2409        if !self.with.is_empty() {
2410            write!(f, " WITH ({})", display_comma_separated(&self.with))?;
2411        }
2412        if let Some(predicate) = &self.predicate {
2413            write!(f, " WHERE {predicate}")?;
2414        }
2415        if !self.index_options.is_empty() {
2416            write!(f, " {}", display_separated(&self.index_options, " "))?;
2417        }
2418        if !self.alter_options.is_empty() {
2419            write!(f, " {}", display_separated(&self.alter_options, " "))?;
2420        }
2421        Ok(())
2422    }
2423}
2424
2425/// CREATE TABLE statement.
2426#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2427#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2428#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2429pub struct CreateTable {
2430    pub or_replace: bool,
2431    pub temporary: bool,
2432    pub external: bool,
2433    pub dynamic: bool,
2434    pub global: Option<bool>,
2435    pub if_not_exists: bool,
2436    pub transient: bool,
2437    pub volatile: bool,
2438    pub iceberg: bool,
2439    /// Table name
2440    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2441    pub name: ObjectName,
2442    /// Optional schema
2443    pub columns: Vec<ColumnDef>,
2444    pub constraints: Vec<TableConstraint>,
2445    pub hive_distribution: HiveDistributionStyle,
2446    pub hive_formats: Option<HiveFormat>,
2447    pub table_options: CreateTableOptions,
2448    pub file_format: Option<FileFormat>,
2449    pub location: Option<String>,
2450    pub query: Option<Box<Query>>,
2451    pub without_rowid: bool,
2452    pub like: Option<CreateTableLikeKind>,
2453    pub clone: Option<ObjectName>,
2454    pub version: Option<TableVersion>,
2455    // For Hive dialect, the table comment is after the column definitions without `=`,
2456    // so the `comment` field is optional and different than the comment field in the general options list.
2457    // [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2458    pub comment: Option<CommentDef>,
2459    pub on_commit: Option<OnCommit>,
2460    /// ClickHouse "ON CLUSTER" clause:
2461    /// <https://clickhouse.com/docs/en/sql-reference/distributed-ddl/>
2462    pub on_cluster: Option<Ident>,
2463    /// ClickHouse "PRIMARY KEY " clause.
2464    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
2465    pub primary_key: Option<Box<Expr>>,
2466    /// ClickHouse "ORDER BY " clause. Note that omitted ORDER BY is different
2467    /// than empty (represented as ()), the latter meaning "no sorting".
2468    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
2469    pub order_by: Option<OneOrManyWithParens<Expr>>,
2470    /// BigQuery: A partition expression for the table.
2471    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#partition_expression>
2472    pub partition_by: Option<Box<Expr>>,
2473    /// BigQuery: Table clustering column list.
2474    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#table_option_list>
2475    /// Snowflake: Table clustering list which contains base column, expressions on base columns.
2476    /// <https://docs.snowflake.com/en/user-guide/tables-clustering-keys#defining-a-clustering-key-for-a-table>
2477    pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
2478    /// Hive: Table clustering column list.
2479    /// <https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable>
2480    pub clustered_by: Option<ClusteredBy>,
2481    /// Postgres `INHERITs` clause, which contains the list of tables from which
2482    /// the new table inherits.
2483    /// <https://www.postgresql.org/docs/current/ddl-inherit.html>
2484    /// <https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-INHERITS>
2485    pub inherits: Option<Vec<ObjectName>>,
2486    /// SQLite "STRICT" clause.
2487    /// if the "STRICT" table-option keyword is added to the end, after the closing ")",
2488    /// then strict typing rules apply to that table.
2489    pub strict: bool,
2490    /// Snowflake "COPY GRANTS" clause
2491    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2492    pub copy_grants: bool,
2493    /// Snowflake "ENABLE_SCHEMA_EVOLUTION" clause
2494    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2495    pub enable_schema_evolution: Option<bool>,
2496    /// Snowflake "CHANGE_TRACKING" clause
2497    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2498    pub change_tracking: Option<bool>,
2499    /// Snowflake "DATA_RETENTION_TIME_IN_DAYS" clause
2500    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2501    pub data_retention_time_in_days: Option<u64>,
2502    /// Snowflake "MAX_DATA_EXTENSION_TIME_IN_DAYS" clause
2503    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2504    pub max_data_extension_time_in_days: Option<u64>,
2505    /// Snowflake "DEFAULT_DDL_COLLATION" clause
2506    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2507    pub default_ddl_collation: Option<String>,
2508    /// Snowflake "WITH AGGREGATION POLICY" clause
2509    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2510    pub with_aggregation_policy: Option<ObjectName>,
2511    /// Snowflake "WITH ROW ACCESS POLICY" clause
2512    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2513    pub with_row_access_policy: Option<RowAccessPolicy>,
2514    /// Snowflake "WITH TAG" clause
2515    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2516    pub with_tags: Option<Vec<Tag>>,
2517    /// Snowflake "EXTERNAL_VOLUME" clause for Iceberg tables
2518    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2519    pub external_volume: Option<String>,
2520    /// Snowflake "BASE_LOCATION" clause for Iceberg tables
2521    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2522    pub base_location: Option<String>,
2523    /// Snowflake "CATALOG" clause for Iceberg tables
2524    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2525    pub catalog: Option<String>,
2526    /// Snowflake "CATALOG_SYNC" clause for Iceberg tables
2527    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2528    pub catalog_sync: Option<String>,
2529    /// Snowflake "STORAGE_SERIALIZATION_POLICY" clause for Iceberg tables
2530    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2531    pub storage_serialization_policy: Option<StorageSerializationPolicy>,
2532    /// Snowflake "TARGET_LAG" clause for dybamic tables
2533    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2534    pub target_lag: Option<String>,
2535    /// Snowflake "WAREHOUSE" clause for dybamic tables
2536    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2537    pub warehouse: Option<Ident>,
2538    /// Snowflake "REFRESH_MODE" clause for dybamic tables
2539    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2540    pub refresh_mode: Option<RefreshModeKind>,
2541    /// Snowflake "INITIALIZE" clause for dybamic tables
2542    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2543    pub initialize: Option<InitializeKind>,
2544    /// Snowflake "REQUIRE USER" clause for dybamic tables
2545    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2546    pub require_user: bool,
2547}
2548
2549impl fmt::Display for CreateTable {
2550    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2551        // We want to allow the following options
2552        // Empty column list, allowed by PostgreSQL:
2553        //   `CREATE TABLE t ()`
2554        // No columns provided for CREATE TABLE AS:
2555        //   `CREATE TABLE t AS SELECT a from t2`
2556        // Columns provided for CREATE TABLE AS:
2557        //   `CREATE TABLE t (a INT) AS SELECT a from t2`
2558        write!(
2559            f,
2560            "CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}{dynamic}{iceberg}TABLE {if_not_exists}{name}",
2561            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
2562            external = if self.external { "EXTERNAL " } else { "" },
2563            global = self.global
2564                .map(|global| {
2565                    if global {
2566                        "GLOBAL "
2567                    } else {
2568                        "LOCAL "
2569                    }
2570                })
2571                .unwrap_or(""),
2572            if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
2573            temporary = if self.temporary { "TEMPORARY " } else { "" },
2574            transient = if self.transient { "TRANSIENT " } else { "" },
2575            volatile = if self.volatile { "VOLATILE " } else { "" },
2576            // Only for Snowflake
2577            iceberg = if self.iceberg { "ICEBERG " } else { "" },
2578            dynamic = if self.dynamic { "DYNAMIC " } else { "" },
2579            name = self.name,
2580        )?;
2581        if let Some(on_cluster) = &self.on_cluster {
2582            write!(f, " ON CLUSTER {on_cluster}")?;
2583        }
2584        if !self.columns.is_empty() || !self.constraints.is_empty() {
2585            f.write_str(" (")?;
2586            NewLine.fmt(f)?;
2587            Indent(DisplayCommaSeparated(&self.columns)).fmt(f)?;
2588            if !self.columns.is_empty() && !self.constraints.is_empty() {
2589                f.write_str(",")?;
2590                SpaceOrNewline.fmt(f)?;
2591            }
2592            Indent(DisplayCommaSeparated(&self.constraints)).fmt(f)?;
2593            NewLine.fmt(f)?;
2594            f.write_str(")")?;
2595        } else if self.query.is_none() && self.like.is_none() && self.clone.is_none() {
2596            // PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
2597            f.write_str(" ()")?;
2598        } else if let Some(CreateTableLikeKind::Parenthesized(like_in_columns_list)) = &self.like {
2599            write!(f, " ({like_in_columns_list})")?;
2600        }
2601
2602        // Hive table comment should be after column definitions, please refer to:
2603        // [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2604        if let Some(comment) = &self.comment {
2605            write!(f, " COMMENT '{comment}'")?;
2606        }
2607
2608        // Only for SQLite
2609        if self.without_rowid {
2610            write!(f, " WITHOUT ROWID")?;
2611        }
2612
2613        if let Some(CreateTableLikeKind::Plain(like)) = &self.like {
2614            write!(f, " {like}")?;
2615        }
2616
2617        if let Some(c) = &self.clone {
2618            write!(f, " CLONE {c}")?;
2619        }
2620
2621        if let Some(version) = &self.version {
2622            write!(f, " {version}")?;
2623        }
2624
2625        match &self.hive_distribution {
2626            HiveDistributionStyle::PARTITIONED { columns } => {
2627                write!(f, " PARTITIONED BY ({})", display_comma_separated(columns))?;
2628            }
2629            HiveDistributionStyle::SKEWED {
2630                columns,
2631                on,
2632                stored_as_directories,
2633            } => {
2634                write!(
2635                    f,
2636                    " SKEWED BY ({})) ON ({})",
2637                    display_comma_separated(columns),
2638                    display_comma_separated(on)
2639                )?;
2640                if *stored_as_directories {
2641                    write!(f, " STORED AS DIRECTORIES")?;
2642                }
2643            }
2644            _ => (),
2645        }
2646
2647        if let Some(clustered_by) = &self.clustered_by {
2648            write!(f, " {clustered_by}")?;
2649        }
2650
2651        if let Some(HiveFormat {
2652            row_format,
2653            serde_properties,
2654            storage,
2655            location,
2656        }) = &self.hive_formats
2657        {
2658            match row_format {
2659                Some(HiveRowFormat::SERDE { class }) => write!(f, " ROW FORMAT SERDE '{class}'")?,
2660                Some(HiveRowFormat::DELIMITED { delimiters }) => {
2661                    write!(f, " ROW FORMAT DELIMITED")?;
2662                    if !delimiters.is_empty() {
2663                        write!(f, " {}", display_separated(delimiters, " "))?;
2664                    }
2665                }
2666                None => (),
2667            }
2668            match storage {
2669                Some(HiveIOFormat::IOF {
2670                    input_format,
2671                    output_format,
2672                }) => write!(
2673                    f,
2674                    " STORED AS INPUTFORMAT {input_format} OUTPUTFORMAT {output_format}"
2675                )?,
2676                Some(HiveIOFormat::FileFormat { format }) if !self.external => {
2677                    write!(f, " STORED AS {format}")?
2678                }
2679                _ => (),
2680            }
2681            if let Some(serde_properties) = serde_properties.as_ref() {
2682                write!(
2683                    f,
2684                    " WITH SERDEPROPERTIES ({})",
2685                    display_comma_separated(serde_properties)
2686                )?;
2687            }
2688            if !self.external {
2689                if let Some(loc) = location {
2690                    write!(f, " LOCATION '{loc}'")?;
2691                }
2692            }
2693        }
2694        if self.external {
2695            if let Some(file_format) = self.file_format {
2696                write!(f, " STORED AS {file_format}")?;
2697            }
2698            write!(f, " LOCATION '{}'", self.location.as_ref().unwrap())?;
2699        }
2700
2701        match &self.table_options {
2702            options @ CreateTableOptions::With(_)
2703            | options @ CreateTableOptions::Plain(_)
2704            | options @ CreateTableOptions::TableProperties(_) => write!(f, " {options}")?,
2705            _ => (),
2706        }
2707
2708        if let Some(primary_key) = &self.primary_key {
2709            write!(f, " PRIMARY KEY {primary_key}")?;
2710        }
2711        if let Some(order_by) = &self.order_by {
2712            write!(f, " ORDER BY {order_by}")?;
2713        }
2714        if let Some(inherits) = &self.inherits {
2715            write!(f, " INHERITS ({})", display_comma_separated(inherits))?;
2716        }
2717        if let Some(partition_by) = self.partition_by.as_ref() {
2718            write!(f, " PARTITION BY {partition_by}")?;
2719        }
2720        if let Some(cluster_by) = self.cluster_by.as_ref() {
2721            write!(f, " CLUSTER BY {cluster_by}")?;
2722        }
2723        if let options @ CreateTableOptions::Options(_) = &self.table_options {
2724            write!(f, " {options}")?;
2725        }
2726        if let Some(external_volume) = self.external_volume.as_ref() {
2727            write!(f, " EXTERNAL_VOLUME='{external_volume}'")?;
2728        }
2729
2730        if let Some(catalog) = self.catalog.as_ref() {
2731            write!(f, " CATALOG='{catalog}'")?;
2732        }
2733
2734        if self.iceberg {
2735            if let Some(base_location) = self.base_location.as_ref() {
2736                write!(f, " BASE_LOCATION='{base_location}'")?;
2737            }
2738        }
2739
2740        if let Some(catalog_sync) = self.catalog_sync.as_ref() {
2741            write!(f, " CATALOG_SYNC='{catalog_sync}'")?;
2742        }
2743
2744        if let Some(storage_serialization_policy) = self.storage_serialization_policy.as_ref() {
2745            write!(
2746                f,
2747                " STORAGE_SERIALIZATION_POLICY={storage_serialization_policy}"
2748            )?;
2749        }
2750
2751        if self.copy_grants {
2752            write!(f, " COPY GRANTS")?;
2753        }
2754
2755        if let Some(is_enabled) = self.enable_schema_evolution {
2756            write!(
2757                f,
2758                " ENABLE_SCHEMA_EVOLUTION={}",
2759                if is_enabled { "TRUE" } else { "FALSE" }
2760            )?;
2761        }
2762
2763        if let Some(is_enabled) = self.change_tracking {
2764            write!(
2765                f,
2766                " CHANGE_TRACKING={}",
2767                if is_enabled { "TRUE" } else { "FALSE" }
2768            )?;
2769        }
2770
2771        if let Some(data_retention_time_in_days) = self.data_retention_time_in_days {
2772            write!(
2773                f,
2774                " DATA_RETENTION_TIME_IN_DAYS={data_retention_time_in_days}",
2775            )?;
2776        }
2777
2778        if let Some(max_data_extension_time_in_days) = self.max_data_extension_time_in_days {
2779            write!(
2780                f,
2781                " MAX_DATA_EXTENSION_TIME_IN_DAYS={max_data_extension_time_in_days}",
2782            )?;
2783        }
2784
2785        if let Some(default_ddl_collation) = &self.default_ddl_collation {
2786            write!(f, " DEFAULT_DDL_COLLATION='{default_ddl_collation}'",)?;
2787        }
2788
2789        if let Some(with_aggregation_policy) = &self.with_aggregation_policy {
2790            write!(f, " WITH AGGREGATION POLICY {with_aggregation_policy}",)?;
2791        }
2792
2793        if let Some(row_access_policy) = &self.with_row_access_policy {
2794            write!(f, " {row_access_policy}",)?;
2795        }
2796
2797        if let Some(tag) = &self.with_tags {
2798            write!(f, " WITH TAG ({})", display_comma_separated(tag.as_slice()))?;
2799        }
2800
2801        if let Some(target_lag) = &self.target_lag {
2802            write!(f, " TARGET_LAG='{target_lag}'")?;
2803        }
2804
2805        if let Some(warehouse) = &self.warehouse {
2806            write!(f, " WAREHOUSE={warehouse}")?;
2807        }
2808
2809        if let Some(refresh_mode) = &self.refresh_mode {
2810            write!(f, " REFRESH_MODE={refresh_mode}")?;
2811        }
2812
2813        if let Some(initialize) = &self.initialize {
2814            write!(f, " INITIALIZE={initialize}")?;
2815        }
2816
2817        if self.require_user {
2818            write!(f, " REQUIRE USER")?;
2819        }
2820
2821        if self.on_commit.is_some() {
2822            let on_commit = match self.on_commit {
2823                Some(OnCommit::DeleteRows) => "ON COMMIT DELETE ROWS",
2824                Some(OnCommit::PreserveRows) => "ON COMMIT PRESERVE ROWS",
2825                Some(OnCommit::Drop) => "ON COMMIT DROP",
2826                None => "",
2827            };
2828            write!(f, " {on_commit}")?;
2829        }
2830        if self.strict {
2831            write!(f, " STRICT")?;
2832        }
2833        if let Some(query) = &self.query {
2834            write!(f, " AS {query}")?;
2835        }
2836        Ok(())
2837    }
2838}
2839
2840#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2841#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2842#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2843/// ```sql
2844/// CREATE DOMAIN name [ AS ] data_type
2845///         [ COLLATE collation ]
2846///         [ DEFAULT expression ]
2847///         [ domain_constraint [ ... ] ]
2848///
2849///     where domain_constraint is:
2850///
2851///     [ CONSTRAINT constraint_name ]
2852///     { NOT NULL | NULL | CHECK (expression) }
2853/// ```
2854/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createdomain.html)
2855pub struct CreateDomain {
2856    /// The name of the domain to be created.
2857    pub name: ObjectName,
2858    /// The data type of the domain.
2859    pub data_type: DataType,
2860    /// The collation of the domain.
2861    pub collation: Option<Ident>,
2862    /// The default value of the domain.
2863    pub default: Option<Expr>,
2864    /// The constraints of the domain.
2865    pub constraints: Vec<TableConstraint>,
2866}
2867
2868impl fmt::Display for CreateDomain {
2869    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2870        write!(
2871            f,
2872            "CREATE DOMAIN {name} AS {data_type}",
2873            name = self.name,
2874            data_type = self.data_type
2875        )?;
2876        if let Some(collation) = &self.collation {
2877            write!(f, " COLLATE {collation}")?;
2878        }
2879        if let Some(default) = &self.default {
2880            write!(f, " DEFAULT {default}")?;
2881        }
2882        if !self.constraints.is_empty() {
2883            write!(f, " {}", display_separated(&self.constraints, " "))?;
2884        }
2885        Ok(())
2886    }
2887}
2888
2889#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2890#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2891#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2892pub struct CreateFunction {
2893    /// True if this is a `CREATE OR ALTER FUNCTION` statement
2894    ///
2895    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql?view=sql-server-ver16#or-alter)
2896    pub or_alter: bool,
2897    pub or_replace: bool,
2898    pub temporary: bool,
2899    pub if_not_exists: bool,
2900    pub name: ObjectName,
2901    pub args: Option<Vec<OperateFunctionArg>>,
2902    pub return_type: Option<DataType>,
2903    /// The expression that defines the function.
2904    ///
2905    /// Examples:
2906    /// ```sql
2907    /// AS ((SELECT 1))
2908    /// AS "console.log();"
2909    /// ```
2910    pub function_body: Option<CreateFunctionBody>,
2911    /// Behavior attribute for the function
2912    ///
2913    /// IMMUTABLE | STABLE | VOLATILE
2914    ///
2915    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
2916    pub behavior: Option<FunctionBehavior>,
2917    /// CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
2918    ///
2919    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
2920    pub called_on_null: Option<FunctionCalledOnNull>,
2921    /// PARALLEL { UNSAFE | RESTRICTED | SAFE }
2922    ///
2923    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
2924    pub parallel: Option<FunctionParallel>,
2925    /// USING ... (Hive only)
2926    pub using: Option<CreateFunctionUsing>,
2927    /// Language used in a UDF definition.
2928    ///
2929    /// Example:
2930    /// ```sql
2931    /// CREATE FUNCTION foo() LANGUAGE js AS "console.log();"
2932    /// ```
2933    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_javascript_udf)
2934    pub language: Option<Ident>,
2935    /// Determinism keyword used for non-sql UDF definitions.
2936    ///
2937    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
2938    pub determinism_specifier: Option<FunctionDeterminismSpecifier>,
2939    /// List of options for creating the function.
2940    ///
2941    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
2942    pub options: Option<Vec<SqlOption>>,
2943    /// Connection resource for a remote function.
2944    ///
2945    /// Example:
2946    /// ```sql
2947    /// CREATE FUNCTION foo()
2948    /// RETURNS FLOAT64
2949    /// REMOTE WITH CONNECTION us.myconnection
2950    /// ```
2951    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
2952    pub remote_connection: Option<ObjectName>,
2953}
2954
2955impl fmt::Display for CreateFunction {
2956    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2957        write!(
2958            f,
2959            "CREATE {or_alter}{or_replace}{temp}FUNCTION {if_not_exists}{name}",
2960            name = self.name,
2961            temp = if self.temporary { "TEMPORARY " } else { "" },
2962            or_alter = if self.or_alter { "OR ALTER " } else { "" },
2963            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
2964            if_not_exists = if self.if_not_exists {
2965                "IF NOT EXISTS "
2966            } else {
2967                ""
2968            },
2969        )?;
2970        if let Some(args) = &self.args {
2971            write!(f, "({})", display_comma_separated(args))?;
2972        }
2973        if let Some(return_type) = &self.return_type {
2974            write!(f, " RETURNS {return_type}")?;
2975        }
2976        if let Some(determinism_specifier) = &self.determinism_specifier {
2977            write!(f, " {determinism_specifier}")?;
2978        }
2979        if let Some(language) = &self.language {
2980            write!(f, " LANGUAGE {language}")?;
2981        }
2982        if let Some(behavior) = &self.behavior {
2983            write!(f, " {behavior}")?;
2984        }
2985        if let Some(called_on_null) = &self.called_on_null {
2986            write!(f, " {called_on_null}")?;
2987        }
2988        if let Some(parallel) = &self.parallel {
2989            write!(f, " {parallel}")?;
2990        }
2991        if let Some(remote_connection) = &self.remote_connection {
2992            write!(f, " REMOTE WITH CONNECTION {remote_connection}")?;
2993        }
2994        if let Some(CreateFunctionBody::AsBeforeOptions(function_body)) = &self.function_body {
2995            write!(f, " AS {function_body}")?;
2996        }
2997        if let Some(CreateFunctionBody::Return(function_body)) = &self.function_body {
2998            write!(f, " RETURN {function_body}")?;
2999        }
3000        if let Some(CreateFunctionBody::AsReturnExpr(function_body)) = &self.function_body {
3001            write!(f, " AS RETURN {function_body}")?;
3002        }
3003        if let Some(CreateFunctionBody::AsReturnSelect(function_body)) = &self.function_body {
3004            write!(f, " AS RETURN {function_body}")?;
3005        }
3006        if let Some(using) = &self.using {
3007            write!(f, " {using}")?;
3008        }
3009        if let Some(options) = &self.options {
3010            write!(
3011                f,
3012                " OPTIONS({})",
3013                display_comma_separated(options.as_slice())
3014            )?;
3015        }
3016        if let Some(CreateFunctionBody::AsAfterOptions(function_body)) = &self.function_body {
3017            write!(f, " AS {function_body}")?;
3018        }
3019        if let Some(CreateFunctionBody::AsBeginEnd(bes)) = &self.function_body {
3020            write!(f, " AS {bes}")?;
3021        }
3022        Ok(())
3023    }
3024}
3025
3026/// ```sql
3027/// CREATE CONNECTOR [IF NOT EXISTS] connector_name
3028/// [TYPE datasource_type]
3029/// [URL datasource_url]
3030/// [COMMENT connector_comment]
3031/// [WITH DCPROPERTIES(property_name=property_value, ...)]
3032/// ```
3033///
3034/// [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
3035#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3036#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3037#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3038pub struct CreateConnector {
3039    pub name: Ident,
3040    pub if_not_exists: bool,
3041    pub connector_type: Option<String>,
3042    pub url: Option<String>,
3043    pub comment: Option<CommentDef>,
3044    pub with_dcproperties: Option<Vec<SqlOption>>,
3045}
3046
3047impl fmt::Display for CreateConnector {
3048    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3049        write!(
3050            f,
3051            "CREATE CONNECTOR {if_not_exists}{name}",
3052            if_not_exists = if self.if_not_exists {
3053                "IF NOT EXISTS "
3054            } else {
3055                ""
3056            },
3057            name = self.name,
3058        )?;
3059
3060        if let Some(connector_type) = &self.connector_type {
3061            write!(f, " TYPE '{connector_type}'")?;
3062        }
3063
3064        if let Some(url) = &self.url {
3065            write!(f, " URL '{url}'")?;
3066        }
3067
3068        if let Some(comment) = &self.comment {
3069            write!(f, " COMMENT = '{comment}'")?;
3070        }
3071
3072        if let Some(with_dcproperties) = &self.with_dcproperties {
3073            write!(
3074                f,
3075                " WITH DCPROPERTIES({})",
3076                display_comma_separated(with_dcproperties)
3077            )?;
3078        }
3079
3080        Ok(())
3081    }
3082}
3083
3084/// An `ALTER SCHEMA` (`Statement::AlterSchema`) operation.
3085///
3086/// See [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#alter_schema_collate_statement)
3087/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterschema.html)
3088#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3089#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3090#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3091pub enum AlterSchemaOperation {
3092    SetDefaultCollate {
3093        collate: Expr,
3094    },
3095    AddReplica {
3096        replica: Ident,
3097        options: Option<Vec<SqlOption>>,
3098    },
3099    DropReplica {
3100        replica: Ident,
3101    },
3102    SetOptionsParens {
3103        options: Vec<SqlOption>,
3104    },
3105    Rename {
3106        name: ObjectName,
3107    },
3108    OwnerTo {
3109        owner: Owner,
3110    },
3111}
3112
3113impl fmt::Display for AlterSchemaOperation {
3114    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3115        match self {
3116            AlterSchemaOperation::SetDefaultCollate { collate } => {
3117                write!(f, "SET DEFAULT COLLATE {collate}")
3118            }
3119            AlterSchemaOperation::AddReplica { replica, options } => {
3120                write!(f, "ADD REPLICA {replica}")?;
3121                if let Some(options) = options {
3122                    write!(f, " OPTIONS ({})", display_comma_separated(options))?;
3123                }
3124                Ok(())
3125            }
3126            AlterSchemaOperation::DropReplica { replica } => write!(f, "DROP REPLICA {replica}"),
3127            AlterSchemaOperation::SetOptionsParens { options } => {
3128                write!(f, "SET OPTIONS ({})", display_comma_separated(options))
3129            }
3130            AlterSchemaOperation::Rename { name } => write!(f, "RENAME TO {name}"),
3131            AlterSchemaOperation::OwnerTo { owner } => write!(f, "OWNER TO {owner}"),
3132        }
3133    }
3134}
3135/// `RenameTableNameKind` is the kind used in an `ALTER TABLE _ RENAME` statement.
3136///
3137/// Note: [MySQL] is the only database that supports the AS keyword for this operation.
3138///
3139/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
3140#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3141#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3142#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3143pub enum RenameTableNameKind {
3144    As(ObjectName),
3145    To(ObjectName),
3146}
3147
3148impl fmt::Display for RenameTableNameKind {
3149    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3150        match self {
3151            RenameTableNameKind::As(name) => write!(f, "AS {name}"),
3152            RenameTableNameKind::To(name) => write!(f, "TO {name}"),
3153        }
3154    }
3155}
3156
3157#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3158#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3159#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3160pub struct AlterSchema {
3161    pub name: ObjectName,
3162    pub if_exists: bool,
3163    pub operations: Vec<AlterSchemaOperation>,
3164}
3165
3166impl fmt::Display for AlterSchema {
3167    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3168        write!(f, "ALTER SCHEMA ")?;
3169        if self.if_exists {
3170            write!(f, "IF EXISTS ")?;
3171        }
3172        write!(f, "{}", self.name)?;
3173        for operation in &self.operations {
3174            write!(f, " {operation}")?;
3175        }
3176
3177        Ok(())
3178    }
3179}
3180
3181impl Spanned for RenameTableNameKind {
3182    fn span(&self) -> Span {
3183        match self {
3184            RenameTableNameKind::As(name) => name.span(),
3185            RenameTableNameKind::To(name) => name.span(),
3186        }
3187    }
3188}
3189
3190#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3191#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3192#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3193/// CREATE TRIGGER
3194///
3195/// Examples:
3196///
3197/// ```sql
3198/// CREATE TRIGGER trigger_name
3199/// BEFORE INSERT ON table_name
3200/// FOR EACH ROW
3201/// EXECUTE FUNCTION trigger_function();
3202/// ```
3203///
3204/// Postgres: <https://www.postgresql.org/docs/current/sql-createtrigger.html>
3205/// SQL Server: <https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql>
3206pub struct CreateTrigger {
3207    /// True if this is a `CREATE OR ALTER TRIGGER` statement
3208    ///
3209    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql?view=sql-server-ver16#arguments)
3210    pub or_alter: bool,
3211    /// The `OR REPLACE` clause is used to re-create the trigger if it already exists.
3212    ///
3213    /// Example:
3214    /// ```sql
3215    /// CREATE OR REPLACE TRIGGER trigger_name
3216    /// AFTER INSERT ON table_name
3217    /// FOR EACH ROW
3218    /// EXECUTE FUNCTION trigger_function();
3219    /// ```
3220    pub or_replace: bool,
3221    /// The `CONSTRAINT` keyword is used to create a trigger as a constraint.
3222    pub is_constraint: bool,
3223    /// The name of the trigger to be created.
3224    pub name: ObjectName,
3225    /// Determines whether the function is called before, after, or instead of the event.
3226    ///
3227    /// Example of BEFORE:
3228    ///
3229    /// ```sql
3230    /// CREATE TRIGGER trigger_name
3231    /// BEFORE INSERT ON table_name
3232    /// FOR EACH ROW
3233    /// EXECUTE FUNCTION trigger_function();
3234    /// ```
3235    ///
3236    /// Example of AFTER:
3237    ///
3238    /// ```sql
3239    /// CREATE TRIGGER trigger_name
3240    /// AFTER INSERT ON table_name
3241    /// FOR EACH ROW
3242    /// EXECUTE FUNCTION trigger_function();
3243    /// ```
3244    ///
3245    /// Example of INSTEAD OF:
3246    ///
3247    /// ```sql
3248    /// CREATE TRIGGER trigger_name
3249    /// INSTEAD OF INSERT ON table_name
3250    /// FOR EACH ROW
3251    /// EXECUTE FUNCTION trigger_function();
3252    /// ```
3253    pub period: TriggerPeriod,
3254    /// Whether the trigger period was specified before the target table name.
3255    ///
3256    /// ```sql
3257    /// -- period_before_table == true: Postgres, MySQL, and standard SQL
3258    /// CREATE TRIGGER t BEFORE INSERT ON table_name ...;
3259    /// -- period_before_table == false: MSSQL
3260    /// CREATE TRIGGER t ON table_name BEFORE INSERT ...;
3261    /// ```
3262    pub period_before_table: bool,
3263    /// Multiple events can be specified using OR, such as `INSERT`, `UPDATE`, `DELETE`, or `TRUNCATE`.
3264    pub events: Vec<TriggerEvent>,
3265    /// The table on which the trigger is to be created.
3266    pub table_name: ObjectName,
3267    /// The optional referenced table name that can be referenced via
3268    /// the `FROM` keyword.
3269    pub referenced_table_name: Option<ObjectName>,
3270    /// This keyword immediately precedes the declaration of one or two relation names that provide access to the transition relations of the triggering statement.
3271    pub referencing: Vec<TriggerReferencing>,
3272    /// This specifies whether the trigger function should be fired once for
3273    /// every row affected by the trigger event, or just once per SQL statement.
3274    pub trigger_object: TriggerObject,
3275    /// Whether to include the `EACH` term of the `FOR EACH`, as it is optional syntax.
3276    pub include_each: bool,
3277    ///  Triggering conditions
3278    pub condition: Option<Expr>,
3279    /// Execute logic block
3280    pub exec_body: Option<TriggerExecBody>,
3281    /// For MSSQL and dialects where statements are preceded by `AS`
3282    pub statements_as: bool,
3283    /// For SQL dialects with statement(s) for a body
3284    pub statements: Option<ConditionalStatements>,
3285    /// The characteristic of the trigger, which include whether the trigger is `DEFERRABLE`, `INITIALLY DEFERRED`, or `INITIALLY IMMEDIATE`,
3286    pub characteristics: Option<ConstraintCharacteristics>,
3287}
3288
3289impl Display for CreateTrigger {
3290    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3291        let CreateTrigger {
3292            or_alter,
3293            or_replace,
3294            is_constraint,
3295            name,
3296            period_before_table,
3297            period,
3298            events,
3299            table_name,
3300            referenced_table_name,
3301            referencing,
3302            trigger_object,
3303            condition,
3304            include_each,
3305            exec_body,
3306            statements_as,
3307            statements,
3308            characteristics,
3309        } = self;
3310        write!(
3311            f,
3312            "CREATE {or_alter}{or_replace}{is_constraint}TRIGGER {name} ",
3313            or_alter = if *or_alter { "OR ALTER " } else { "" },
3314            or_replace = if *or_replace { "OR REPLACE " } else { "" },
3315            is_constraint = if *is_constraint { "CONSTRAINT " } else { "" },
3316        )?;
3317
3318        if *period_before_table {
3319            write!(f, "{period}")?;
3320            if !events.is_empty() {
3321                write!(f, " {}", display_separated(events, " OR "))?;
3322            }
3323            write!(f, " ON {table_name}")?;
3324        } else {
3325            write!(f, "ON {table_name}")?;
3326            write!(f, " {period}")?;
3327            if !events.is_empty() {
3328                write!(f, " {}", display_separated(events, ", "))?;
3329            }
3330        }
3331
3332        if let Some(referenced_table_name) = referenced_table_name {
3333            write!(f, " FROM {referenced_table_name}")?;
3334        }
3335
3336        if let Some(characteristics) = characteristics {
3337            write!(f, " {characteristics}")?;
3338        }
3339
3340        if !referencing.is_empty() {
3341            write!(f, " REFERENCING {}", display_separated(referencing, " "))?;
3342        }
3343
3344        if *include_each {
3345            write!(f, " FOR EACH {trigger_object}")?;
3346        } else if exec_body.is_some() {
3347            write!(f, " FOR {trigger_object}")?;
3348        }
3349        if let Some(condition) = condition {
3350            write!(f, " WHEN {condition}")?;
3351        }
3352        if let Some(exec_body) = exec_body {
3353            write!(f, " EXECUTE {exec_body}")?;
3354        }
3355        if let Some(statements) = statements {
3356            if *statements_as {
3357                write!(f, " AS")?;
3358            }
3359            write!(f, " {statements}")?;
3360        }
3361        Ok(())
3362    }
3363}
3364
3365#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3366#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3367#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3368/// DROP TRIGGER
3369///
3370/// ```sql
3371/// DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
3372/// ```
3373///
3374pub struct DropTrigger {
3375    /// Whether to include the `IF EXISTS` clause.
3376    pub if_exists: bool,
3377    /// The name of the trigger to be dropped.
3378    pub trigger_name: ObjectName,
3379    /// The name of the table from which the trigger is to be dropped.
3380    pub table_name: Option<ObjectName>,
3381    /// `CASCADE` or `RESTRICT`
3382    pub option: Option<ReferentialAction>,
3383}
3384
3385impl fmt::Display for DropTrigger {
3386    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3387        let DropTrigger {
3388            if_exists,
3389            trigger_name,
3390            table_name,
3391            option,
3392        } = self;
3393        write!(f, "DROP TRIGGER")?;
3394        if *if_exists {
3395            write!(f, " IF EXISTS")?;
3396        }
3397        match &table_name {
3398            Some(table_name) => write!(f, " {trigger_name} ON {table_name}")?,
3399            None => write!(f, " {trigger_name}")?,
3400        };
3401        if let Some(option) = option {
3402            write!(f, " {option}")?;
3403        }
3404        Ok(())
3405    }
3406}