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