Skip to main content

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::{
23    boxed::Box,
24    format,
25    string::{String, ToString},
26    vec,
27    vec::Vec,
28};
29use core::fmt::{self, Display, Write};
30
31#[cfg(feature = "serde")]
32use serde::{Deserialize, Serialize};
33
34#[cfg(feature = "visitor")]
35use sqlparser_derive::{Visit, VisitMut};
36
37use crate::ast::value::escape_single_quote_string;
38use crate::ast::{
39    display_comma_separated, display_separated,
40    table_constraints::{
41        CheckConstraint, ForeignKeyConstraint, PrimaryKeyConstraint, TableConstraint,
42        UniqueConstraint,
43    },
44    ArgMode, AttachedToken, CommentDef, ConditionalStatements, CreateFunctionBody,
45    CreateFunctionUsing, CreateTableLikeKind, CreateTableOptions, CreateViewParams, DataType, Expr,
46    FileFormat, FunctionBehavior, FunctionCalledOnNull, FunctionDefinitionSetParam, FunctionDesc,
47    FunctionDeterminismSpecifier, FunctionParallel, FunctionSecurity, HiveDistributionStyle,
48    HiveFormat, HiveIOFormat, HiveRowFormat, HiveSetLocation, Ident, InitializeKind,
49    MySQLColumnPosition, ObjectName, OnCommit, OneOrManyWithParens, OperateFunctionArg,
50    OrderByExpr, ProjectionSelect, Query, RefreshModeKind, RowAccessPolicy, SequenceOptions,
51    Spanned, SqlOption, StorageSerializationPolicy, TableVersion, Tag, TriggerEvent,
52    TriggerExecBody, TriggerObject, TriggerPeriod, TriggerReferencing, Value, ValueWithSpan,
53    WrappedCollection,
54};
55use crate::display_utils::{DisplayCommaSeparated, Indent, NewLine, SpaceOrNewline};
56use crate::keywords::Keyword;
57use crate::tokenizer::{Span, Token};
58
59/// Index column type.
60#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
61#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
62#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
63pub struct IndexColumn {
64    pub column: OrderByExpr,
65    pub operator_class: Option<Ident>,
66}
67
68impl From<Ident> for IndexColumn {
69    fn from(c: Ident) -> Self {
70        Self {
71            column: OrderByExpr::from(c),
72            operator_class: None,
73        }
74    }
75}
76
77impl<'a> From<&'a str> for IndexColumn {
78    fn from(c: &'a str) -> Self {
79        let ident = Ident::new(c);
80        ident.into()
81    }
82}
83
84impl fmt::Display for IndexColumn {
85    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86        write!(f, "{}", self.column)?;
87        if let Some(operator_class) = &self.operator_class {
88            write!(f, " {operator_class}")?;
89        }
90        Ok(())
91    }
92}
93
94/// ALTER TABLE operation REPLICA IDENTITY values
95/// See [Postgres ALTER TABLE docs](https://www.postgresql.org/docs/current/sql-altertable.html)
96#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
97#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
98#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
99pub enum ReplicaIdentity {
100    None,
101    Full,
102    Default,
103    Index(Ident),
104}
105
106impl fmt::Display for ReplicaIdentity {
107    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108        match self {
109            ReplicaIdentity::None => f.write_str("NONE"),
110            ReplicaIdentity::Full => f.write_str("FULL"),
111            ReplicaIdentity::Default => f.write_str("DEFAULT"),
112            ReplicaIdentity::Index(idx) => write!(f, "USING INDEX {idx}"),
113        }
114    }
115}
116
117/// An `ALTER TABLE` (`Statement::AlterTable`) operation
118#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
119#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
120#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
121pub enum AlterTableOperation {
122    /// `ADD <table_constraint> [NOT VALID]`
123    AddConstraint {
124        constraint: TableConstraint,
125        not_valid: bool,
126    },
127    /// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
128    AddColumn {
129        /// `[COLUMN]`.
130        column_keyword: bool,
131        /// `[IF NOT EXISTS]`
132        if_not_exists: bool,
133        /// <column_def>.
134        column_def: ColumnDef,
135        /// MySQL `ALTER TABLE` only  [FIRST | AFTER column_name]
136        column_position: Option<MySQLColumnPosition>,
137    },
138    /// `ADD PROJECTION [IF NOT EXISTS] name ( SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY])`
139    ///
140    /// Note: this is a ClickHouse-specific operation.
141    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#add-projection)
142    AddProjection {
143        if_not_exists: bool,
144        name: Ident,
145        select: ProjectionSelect,
146    },
147    /// `DROP PROJECTION [IF EXISTS] name`
148    ///
149    /// Note: this is a ClickHouse-specific operation.
150    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#drop-projection)
151    DropProjection {
152        if_exists: bool,
153        name: Ident,
154    },
155    /// `MATERIALIZE PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
156    ///
157    ///  Note: this is a ClickHouse-specific operation.
158    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#materialize-projection)
159    MaterializeProjection {
160        if_exists: bool,
161        name: Ident,
162        partition: Option<Ident>,
163    },
164    /// `CLEAR PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
165    ///
166    /// Note: this is a ClickHouse-specific operation.
167    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#clear-projection)
168    ClearProjection {
169        if_exists: bool,
170        name: Ident,
171        partition: Option<Ident>,
172    },
173    /// `DISABLE ROW LEVEL SECURITY`
174    ///
175    /// Note: this is a PostgreSQL-specific operation.
176    DisableRowLevelSecurity,
177    /// `DISABLE RULE rewrite_rule_name`
178    ///
179    /// Note: this is a PostgreSQL-specific operation.
180    DisableRule {
181        name: Ident,
182    },
183    /// `DISABLE TRIGGER [ trigger_name | ALL | USER ]`
184    ///
185    /// Note: this is a PostgreSQL-specific operation.
186    DisableTrigger {
187        name: Ident,
188    },
189    /// `DROP CONSTRAINT [ IF EXISTS ] <name>`
190    DropConstraint {
191        if_exists: bool,
192        name: Ident,
193        drop_behavior: Option<DropBehavior>,
194    },
195    /// `DROP [ COLUMN ] [ IF EXISTS ] <column_name> [ , <column_name>, ... ] [ CASCADE ]`
196    DropColumn {
197        has_column_keyword: bool,
198        column_names: Vec<Ident>,
199        if_exists: bool,
200        drop_behavior: Option<DropBehavior>,
201    },
202    /// `ATTACH PART|PARTITION <partition_expr>`
203    /// Note: this is a ClickHouse-specific operation, please refer to
204    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
205    AttachPartition {
206        // PART is not a short form of PARTITION, it's a separate keyword
207        // which represents a physical file on disk and partition is a logical entity.
208        partition: Partition,
209    },
210    /// `DETACH PART|PARTITION <partition_expr>`
211    /// Note: this is a ClickHouse-specific operation, please refer to
212    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#detach-partitionpart)
213    DetachPartition {
214        // See `AttachPartition` for more details
215        partition: Partition,
216    },
217    /// `FREEZE PARTITION <partition_expr>`
218    /// Note: this is a ClickHouse-specific operation, please refer to
219    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#freeze-partition)
220    FreezePartition {
221        partition: Partition,
222        with_name: Option<Ident>,
223    },
224    /// `UNFREEZE PARTITION <partition_expr>`
225    /// Note: this is a ClickHouse-specific operation, please refer to
226    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#unfreeze-partition)
227    UnfreezePartition {
228        partition: Partition,
229        with_name: Option<Ident>,
230    },
231    /// `DROP PRIMARY KEY`
232    ///
233    /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/alter-table.html)
234    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constraints-drop)
235    DropPrimaryKey {
236        drop_behavior: Option<DropBehavior>,
237    },
238    /// `DROP FOREIGN KEY <fk_symbol>`
239    ///
240    /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/alter-table.html)
241    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constraints-drop)
242    DropForeignKey {
243        name: Ident,
244        drop_behavior: Option<DropBehavior>,
245    },
246    /// `DROP INDEX <index_name>`
247    ///
248    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
249    DropIndex {
250        name: Ident,
251    },
252    /// `ENABLE ALWAYS RULE rewrite_rule_name`
253    ///
254    /// Note: this is a PostgreSQL-specific operation.
255    EnableAlwaysRule {
256        name: Ident,
257    },
258    /// `ENABLE ALWAYS TRIGGER trigger_name`
259    ///
260    /// Note: this is a PostgreSQL-specific operation.
261    EnableAlwaysTrigger {
262        name: Ident,
263    },
264    /// `ENABLE REPLICA RULE rewrite_rule_name`
265    ///
266    /// Note: this is a PostgreSQL-specific operation.
267    EnableReplicaRule {
268        name: Ident,
269    },
270    /// `ENABLE REPLICA TRIGGER trigger_name`
271    ///
272    /// Note: this is a PostgreSQL-specific operation.
273    EnableReplicaTrigger {
274        name: Ident,
275    },
276    /// `ENABLE ROW LEVEL SECURITY`
277    ///
278    /// Note: this is a PostgreSQL-specific operation.
279    EnableRowLevelSecurity,
280    /// `FORCE ROW LEVEL SECURITY`
281    ///
282    /// Note: this is a PostgreSQL-specific operation.
283    ForceRowLevelSecurity,
284    /// `NO FORCE ROW LEVEL SECURITY`
285    ///
286    /// Note: this is a PostgreSQL-specific operation.
287    NoForceRowLevelSecurity,
288    /// `ENABLE RULE rewrite_rule_name`
289    ///
290    /// Note: this is a PostgreSQL-specific operation.
291    EnableRule {
292        name: Ident,
293    },
294    /// `ENABLE TRIGGER [ trigger_name | ALL | USER ]`
295    ///
296    /// Note: this is a PostgreSQL-specific operation.
297    EnableTrigger {
298        name: Ident,
299    },
300    /// `RENAME TO PARTITION (partition=val)`
301    RenamePartitions {
302        old_partitions: Vec<Expr>,
303        new_partitions: Vec<Expr>,
304    },
305    /// REPLICA IDENTITY { DEFAULT | USING INDEX index_name | FULL | NOTHING }
306    ///
307    /// Note: this is a PostgreSQL-specific operation.
308    /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
309    ReplicaIdentity {
310        identity: ReplicaIdentity,
311    },
312    /// Add Partitions
313    AddPartitions {
314        if_not_exists: bool,
315        new_partitions: Vec<Partition>,
316    },
317    DropPartitions {
318        partitions: Vec<Expr>,
319        if_exists: bool,
320    },
321    /// `RENAME [ COLUMN ] <old_column_name> TO <new_column_name>`
322    RenameColumn {
323        old_column_name: Ident,
324        new_column_name: Ident,
325    },
326    /// `RENAME TO <table_name>`
327    RenameTable {
328        table_name: RenameTableNameKind,
329    },
330    // CHANGE [ COLUMN ] <old_name> <new_name> <data_type> [ <options> ]
331    ChangeColumn {
332        old_name: Ident,
333        new_name: Ident,
334        data_type: DataType,
335        options: Vec<ColumnOption>,
336        /// MySQL `ALTER TABLE` only  [FIRST | AFTER column_name]
337        column_position: Option<MySQLColumnPosition>,
338    },
339    // CHANGE [ COLUMN ] <col_name> <data_type> [ <options> ]
340    ModifyColumn {
341        col_name: Ident,
342        data_type: DataType,
343        options: Vec<ColumnOption>,
344        /// MySQL `ALTER TABLE` only  [FIRST | AFTER column_name]
345        column_position: Option<MySQLColumnPosition>,
346    },
347    /// `RENAME CONSTRAINT <old_constraint_name> TO <new_constraint_name>`
348    ///
349    /// Note: this is a PostgreSQL-specific operation.
350    RenameConstraint {
351        old_name: Ident,
352        new_name: Ident,
353    },
354    /// `ALTER [ COLUMN ]`
355    AlterColumn {
356        column_name: Ident,
357        op: AlterColumnOperation,
358    },
359    /// 'SWAP WITH <table_name>'
360    ///
361    /// Note: this is Snowflake specific <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
362    SwapWith {
363        table_name: ObjectName,
364    },
365    /// 'SET TBLPROPERTIES ( { property_key [ = ] property_val } [, ...] )'
366    SetTblProperties {
367        table_properties: Vec<SqlOption>,
368    },
369    /// `OWNER TO { <new_owner> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
370    ///
371    /// Note: this is PostgreSQL-specific <https://www.postgresql.org/docs/current/sql-altertable.html>
372    OwnerTo {
373        new_owner: Owner,
374    },
375    /// Snowflake table clustering options
376    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-table#clustering-actions-clusteringaction>
377    ClusterBy {
378        exprs: Vec<Expr>,
379    },
380    DropClusteringKey,
381    SuspendRecluster,
382    ResumeRecluster,
383    /// `REFRESH`
384    ///
385    /// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
386    Refresh,
387    /// `SUSPEND`
388    ///
389    /// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
390    Suspend,
391    /// `RESUME`
392    ///
393    /// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
394    Resume,
395    /// `ALGORITHM [=] { DEFAULT | INSTANT | INPLACE | COPY }`
396    ///
397    /// [MySQL]-specific table alter algorithm.
398    ///
399    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
400    Algorithm {
401        equals: bool,
402        algorithm: AlterTableAlgorithm,
403    },
404
405    /// `LOCK [=] { DEFAULT | NONE | SHARED | EXCLUSIVE }`
406    ///
407    /// [MySQL]-specific table alter lock.
408    ///
409    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
410    Lock {
411        equals: bool,
412        lock: AlterTableLock,
413    },
414    /// `AUTO_INCREMENT [=] <value>`
415    ///
416    /// [MySQL]-specific table option for raising current auto increment value.
417    ///
418    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
419    AutoIncrement {
420        equals: bool,
421        value: ValueWithSpan,
422    },
423    /// `VALIDATE CONSTRAINT <name>`
424    ValidateConstraint {
425        name: Ident,
426    },
427    /// Arbitrary parenthesized `SET` options.
428    ///
429    /// Example:
430    /// ```sql
431    /// SET (scale_factor = 0.01, threshold = 500)`
432    /// ```
433    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-altertable.html)
434    SetOptionsParens {
435        options: Vec<SqlOption>,
436    },
437}
438
439/// An `ALTER Policy` (`Statement::AlterPolicy`) operation
440///
441/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
442#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
443#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
444#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
445pub enum AlterPolicyOperation {
446    Rename {
447        new_name: Ident,
448    },
449    Apply {
450        to: Option<Vec<Owner>>,
451        using: Option<Expr>,
452        with_check: Option<Expr>,
453    },
454}
455
456impl fmt::Display for AlterPolicyOperation {
457    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
458        match self {
459            AlterPolicyOperation::Rename { new_name } => {
460                write!(f, " RENAME TO {new_name}")
461            }
462            AlterPolicyOperation::Apply {
463                to,
464                using,
465                with_check,
466            } => {
467                if let Some(to) = to {
468                    write!(f, " TO {}", display_comma_separated(to))?;
469                }
470                if let Some(using) = using {
471                    write!(f, " USING ({using})")?;
472                }
473                if let Some(with_check) = with_check {
474                    write!(f, " WITH CHECK ({with_check})")?;
475                }
476                Ok(())
477            }
478        }
479    }
480}
481
482/// [MySQL] `ALTER TABLE` algorithm.
483///
484/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
485#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
486#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
487#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
488pub enum AlterTableAlgorithm {
489    Default,
490    Instant,
491    Inplace,
492    Copy,
493}
494
495impl fmt::Display for AlterTableAlgorithm {
496    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
497        f.write_str(match self {
498            Self::Default => "DEFAULT",
499            Self::Instant => "INSTANT",
500            Self::Inplace => "INPLACE",
501            Self::Copy => "COPY",
502        })
503    }
504}
505
506/// [MySQL] `ALTER TABLE` lock.
507///
508/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
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 AlterTableLock {
513    Default,
514    None,
515    Shared,
516    Exclusive,
517}
518
519impl fmt::Display for AlterTableLock {
520    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
521        f.write_str(match self {
522            Self::Default => "DEFAULT",
523            Self::None => "NONE",
524            Self::Shared => "SHARED",
525            Self::Exclusive => "EXCLUSIVE",
526        })
527    }
528}
529
530#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
531#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
532#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
533pub enum Owner {
534    Ident(Ident),
535    CurrentRole,
536    CurrentUser,
537    SessionUser,
538}
539
540impl fmt::Display for Owner {
541    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
542        match self {
543            Owner::Ident(ident) => write!(f, "{ident}"),
544            Owner::CurrentRole => write!(f, "CURRENT_ROLE"),
545            Owner::CurrentUser => write!(f, "CURRENT_USER"),
546            Owner::SessionUser => write!(f, "SESSION_USER"),
547        }
548    }
549}
550
551#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
552#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
553#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
554pub enum AlterConnectorOwner {
555    User(Ident),
556    Role(Ident),
557}
558
559impl fmt::Display for AlterConnectorOwner {
560    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
561        match self {
562            AlterConnectorOwner::User(ident) => write!(f, "USER {ident}"),
563            AlterConnectorOwner::Role(ident) => write!(f, "ROLE {ident}"),
564        }
565    }
566}
567
568#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
569#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
570#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
571pub enum AlterIndexOperation {
572    RenameIndex { index_name: ObjectName },
573}
574
575impl fmt::Display for AlterTableOperation {
576    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
577        match self {
578            AlterTableOperation::AddPartitions {
579                if_not_exists,
580                new_partitions,
581            } => write!(
582                f,
583                "ADD{ine} {}",
584                display_separated(new_partitions, " "),
585                ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
586            ),
587            AlterTableOperation::AddConstraint {
588                not_valid,
589                constraint,
590            } => {
591                write!(f, "ADD {constraint}")?;
592                if *not_valid {
593                    write!(f, " NOT VALID")?;
594                }
595                Ok(())
596            }
597            AlterTableOperation::AddColumn {
598                column_keyword,
599                if_not_exists,
600                column_def,
601                column_position,
602            } => {
603                write!(f, "ADD")?;
604                if *column_keyword {
605                    write!(f, " COLUMN")?;
606                }
607                if *if_not_exists {
608                    write!(f, " IF NOT EXISTS")?;
609                }
610                write!(f, " {column_def}")?;
611
612                if let Some(position) = column_position {
613                    write!(f, " {position}")?;
614                }
615
616                Ok(())
617            }
618            AlterTableOperation::AddProjection {
619                if_not_exists,
620                name,
621                select: query,
622            } => {
623                write!(f, "ADD PROJECTION")?;
624                if *if_not_exists {
625                    write!(f, " IF NOT EXISTS")?;
626                }
627                write!(f, " {name} ({query})")
628            }
629            AlterTableOperation::Algorithm { equals, algorithm } => {
630                write!(
631                    f,
632                    "ALGORITHM {}{}",
633                    if *equals { "= " } else { "" },
634                    algorithm
635                )
636            }
637            AlterTableOperation::DropProjection { if_exists, name } => {
638                write!(f, "DROP PROJECTION")?;
639                if *if_exists {
640                    write!(f, " IF EXISTS")?;
641                }
642                write!(f, " {name}")
643            }
644            AlterTableOperation::MaterializeProjection {
645                if_exists,
646                name,
647                partition,
648            } => {
649                write!(f, "MATERIALIZE PROJECTION")?;
650                if *if_exists {
651                    write!(f, " IF EXISTS")?;
652                }
653                write!(f, " {name}")?;
654                if let Some(partition) = partition {
655                    write!(f, " IN PARTITION {partition}")?;
656                }
657                Ok(())
658            }
659            AlterTableOperation::ClearProjection {
660                if_exists,
661                name,
662                partition,
663            } => {
664                write!(f, "CLEAR PROJECTION")?;
665                if *if_exists {
666                    write!(f, " IF EXISTS")?;
667                }
668                write!(f, " {name}")?;
669                if let Some(partition) = partition {
670                    write!(f, " IN PARTITION {partition}")?;
671                }
672                Ok(())
673            }
674            AlterTableOperation::AlterColumn { column_name, op } => {
675                write!(f, "ALTER COLUMN {column_name} {op}")
676            }
677            AlterTableOperation::DisableRowLevelSecurity => {
678                write!(f, "DISABLE ROW LEVEL SECURITY")
679            }
680            AlterTableOperation::DisableRule { name } => {
681                write!(f, "DISABLE RULE {name}")
682            }
683            AlterTableOperation::DisableTrigger { name } => {
684                write!(f, "DISABLE TRIGGER {name}")
685            }
686            AlterTableOperation::DropPartitions {
687                partitions,
688                if_exists,
689            } => write!(
690                f,
691                "DROP{ie} PARTITION ({})",
692                display_comma_separated(partitions),
693                ie = if *if_exists { " IF EXISTS" } else { "" }
694            ),
695            AlterTableOperation::DropConstraint {
696                if_exists,
697                name,
698                drop_behavior,
699            } => {
700                write!(
701                    f,
702                    "DROP CONSTRAINT {}{}",
703                    if *if_exists { "IF EXISTS " } else { "" },
704                    name
705                )?;
706                if let Some(drop_behavior) = drop_behavior {
707                    write!(f, " {drop_behavior}")?;
708                }
709                Ok(())
710            }
711            AlterTableOperation::DropPrimaryKey { drop_behavior } => {
712                write!(f, "DROP PRIMARY KEY")?;
713                if let Some(drop_behavior) = drop_behavior {
714                    write!(f, " {drop_behavior}")?;
715                }
716                Ok(())
717            }
718            AlterTableOperation::DropForeignKey {
719                name,
720                drop_behavior,
721            } => {
722                write!(f, "DROP FOREIGN KEY {name}")?;
723                if let Some(drop_behavior) = drop_behavior {
724                    write!(f, " {drop_behavior}")?;
725                }
726                Ok(())
727            }
728            AlterTableOperation::DropIndex { name } => write!(f, "DROP INDEX {name}"),
729            AlterTableOperation::DropColumn {
730                has_column_keyword,
731                column_names: column_name,
732                if_exists,
733                drop_behavior,
734            } => {
735                write!(
736                    f,
737                    "DROP {}{}{}",
738                    if *has_column_keyword { "COLUMN " } else { "" },
739                    if *if_exists { "IF EXISTS " } else { "" },
740                    display_comma_separated(column_name),
741                )?;
742                if let Some(drop_behavior) = drop_behavior {
743                    write!(f, " {drop_behavior}")?;
744                }
745                Ok(())
746            }
747            AlterTableOperation::AttachPartition { partition } => {
748                write!(f, "ATTACH {partition}")
749            }
750            AlterTableOperation::DetachPartition { partition } => {
751                write!(f, "DETACH {partition}")
752            }
753            AlterTableOperation::EnableAlwaysRule { name } => {
754                write!(f, "ENABLE ALWAYS RULE {name}")
755            }
756            AlterTableOperation::EnableAlwaysTrigger { name } => {
757                write!(f, "ENABLE ALWAYS TRIGGER {name}")
758            }
759            AlterTableOperation::EnableReplicaRule { name } => {
760                write!(f, "ENABLE REPLICA RULE {name}")
761            }
762            AlterTableOperation::EnableReplicaTrigger { name } => {
763                write!(f, "ENABLE REPLICA TRIGGER {name}")
764            }
765            AlterTableOperation::EnableRowLevelSecurity => {
766                write!(f, "ENABLE ROW LEVEL SECURITY")
767            }
768            AlterTableOperation::ForceRowLevelSecurity => {
769                write!(f, "FORCE ROW LEVEL SECURITY")
770            }
771            AlterTableOperation::NoForceRowLevelSecurity => {
772                write!(f, "NO FORCE ROW LEVEL SECURITY")
773            }
774            AlterTableOperation::EnableRule { name } => {
775                write!(f, "ENABLE RULE {name}")
776            }
777            AlterTableOperation::EnableTrigger { name } => {
778                write!(f, "ENABLE TRIGGER {name}")
779            }
780            AlterTableOperation::RenamePartitions {
781                old_partitions,
782                new_partitions,
783            } => write!(
784                f,
785                "PARTITION ({}) RENAME TO PARTITION ({})",
786                display_comma_separated(old_partitions),
787                display_comma_separated(new_partitions)
788            ),
789            AlterTableOperation::RenameColumn {
790                old_column_name,
791                new_column_name,
792            } => write!(f, "RENAME COLUMN {old_column_name} TO {new_column_name}"),
793            AlterTableOperation::RenameTable { table_name } => {
794                write!(f, "RENAME {table_name}")
795            }
796            AlterTableOperation::ChangeColumn {
797                old_name,
798                new_name,
799                data_type,
800                options,
801                column_position,
802            } => {
803                write!(f, "CHANGE COLUMN {old_name} {new_name} {data_type}")?;
804                if !options.is_empty() {
805                    write!(f, " {}", display_separated(options, " "))?;
806                }
807                if let Some(position) = column_position {
808                    write!(f, " {position}")?;
809                }
810
811                Ok(())
812            }
813            AlterTableOperation::ModifyColumn {
814                col_name,
815                data_type,
816                options,
817                column_position,
818            } => {
819                write!(f, "MODIFY COLUMN {col_name} {data_type}")?;
820                if !options.is_empty() {
821                    write!(f, " {}", display_separated(options, " "))?;
822                }
823                if let Some(position) = column_position {
824                    write!(f, " {position}")?;
825                }
826
827                Ok(())
828            }
829            AlterTableOperation::RenameConstraint { old_name, new_name } => {
830                write!(f, "RENAME CONSTRAINT {old_name} TO {new_name}")
831            }
832            AlterTableOperation::SwapWith { table_name } => {
833                write!(f, "SWAP WITH {table_name}")
834            }
835            AlterTableOperation::OwnerTo { new_owner } => {
836                write!(f, "OWNER TO {new_owner}")
837            }
838            AlterTableOperation::SetTblProperties { table_properties } => {
839                write!(
840                    f,
841                    "SET TBLPROPERTIES({})",
842                    display_comma_separated(table_properties)
843                )
844            }
845            AlterTableOperation::FreezePartition {
846                partition,
847                with_name,
848            } => {
849                write!(f, "FREEZE {partition}")?;
850                if let Some(name) = with_name {
851                    write!(f, " WITH NAME {name}")?;
852                }
853                Ok(())
854            }
855            AlterTableOperation::UnfreezePartition {
856                partition,
857                with_name,
858            } => {
859                write!(f, "UNFREEZE {partition}")?;
860                if let Some(name) = with_name {
861                    write!(f, " WITH NAME {name}")?;
862                }
863                Ok(())
864            }
865            AlterTableOperation::ClusterBy { exprs } => {
866                write!(f, "CLUSTER BY ({})", display_comma_separated(exprs))?;
867                Ok(())
868            }
869            AlterTableOperation::DropClusteringKey => {
870                write!(f, "DROP CLUSTERING KEY")?;
871                Ok(())
872            }
873            AlterTableOperation::SuspendRecluster => {
874                write!(f, "SUSPEND RECLUSTER")?;
875                Ok(())
876            }
877            AlterTableOperation::ResumeRecluster => {
878                write!(f, "RESUME RECLUSTER")?;
879                Ok(())
880            }
881            AlterTableOperation::Refresh => {
882                write!(f, "REFRESH")
883            }
884            AlterTableOperation::Suspend => {
885                write!(f, "SUSPEND")
886            }
887            AlterTableOperation::Resume => {
888                write!(f, "RESUME")
889            }
890            AlterTableOperation::AutoIncrement { equals, value } => {
891                write!(
892                    f,
893                    "AUTO_INCREMENT {}{}",
894                    if *equals { "= " } else { "" },
895                    value
896                )
897            }
898            AlterTableOperation::Lock { equals, lock } => {
899                write!(f, "LOCK {}{}", if *equals { "= " } else { "" }, lock)
900            }
901            AlterTableOperation::ReplicaIdentity { identity } => {
902                write!(f, "REPLICA IDENTITY {identity}")
903            }
904            AlterTableOperation::ValidateConstraint { name } => {
905                write!(f, "VALIDATE CONSTRAINT {name}")
906            }
907            AlterTableOperation::SetOptionsParens { options } => {
908                write!(f, "SET ({})", display_comma_separated(options))
909            }
910        }
911    }
912}
913
914impl fmt::Display for AlterIndexOperation {
915    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
916        match self {
917            AlterIndexOperation::RenameIndex { index_name } => {
918                write!(f, "RENAME TO {index_name}")
919            }
920        }
921    }
922}
923
924/// An `ALTER TYPE` statement (`Statement::AlterType`)
925#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
926#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
927#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
928pub struct AlterType {
929    pub name: ObjectName,
930    pub operation: AlterTypeOperation,
931}
932
933/// An [AlterType] operation
934#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
935#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
936#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
937pub enum AlterTypeOperation {
938    Rename(AlterTypeRename),
939    AddValue(AlterTypeAddValue),
940    RenameValue(AlterTypeRenameValue),
941}
942
943/// See [AlterTypeOperation::Rename]
944#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
945#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
946#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
947pub struct AlterTypeRename {
948    pub new_name: Ident,
949}
950
951/// See [AlterTypeOperation::AddValue]
952#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
953#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
954#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
955pub struct AlterTypeAddValue {
956    pub if_not_exists: bool,
957    pub value: Ident,
958    pub position: Option<AlterTypeAddValuePosition>,
959}
960
961/// See [AlterTypeAddValue]
962#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
963#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
964#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
965pub enum AlterTypeAddValuePosition {
966    Before(Ident),
967    After(Ident),
968}
969
970/// See [AlterTypeOperation::RenameValue]
971#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
972#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
973#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
974pub struct AlterTypeRenameValue {
975    pub from: Ident,
976    pub to: Ident,
977}
978
979impl fmt::Display for AlterTypeOperation {
980    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
981        match self {
982            Self::Rename(AlterTypeRename { new_name }) => {
983                write!(f, "RENAME TO {new_name}")
984            }
985            Self::AddValue(AlterTypeAddValue {
986                if_not_exists,
987                value,
988                position,
989            }) => {
990                write!(f, "ADD VALUE")?;
991                if *if_not_exists {
992                    write!(f, " IF NOT EXISTS")?;
993                }
994                write!(f, " {value}")?;
995                match position {
996                    Some(AlterTypeAddValuePosition::Before(neighbor_value)) => {
997                        write!(f, " BEFORE {neighbor_value}")?;
998                    }
999                    Some(AlterTypeAddValuePosition::After(neighbor_value)) => {
1000                        write!(f, " AFTER {neighbor_value}")?;
1001                    }
1002                    None => {}
1003                };
1004                Ok(())
1005            }
1006            Self::RenameValue(AlterTypeRenameValue { from, to }) => {
1007                write!(f, "RENAME VALUE {from} TO {to}")
1008            }
1009        }
1010    }
1011}
1012
1013/// `ALTER OPERATOR` statement
1014/// See <https://www.postgresql.org/docs/current/sql-alteroperator.html>
1015#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1016#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1017#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1018pub struct AlterOperator {
1019    /// Operator name (can be schema-qualified)
1020    pub name: ObjectName,
1021    /// Left operand type (`None` if no left operand)
1022    pub left_type: Option<DataType>,
1023    /// Right operand type
1024    pub right_type: DataType,
1025    /// The operation to perform
1026    pub operation: AlterOperatorOperation,
1027}
1028
1029/// An [AlterOperator] operation
1030#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1031#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1032#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1033pub enum AlterOperatorOperation {
1034    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
1035    OwnerTo(Owner),
1036    /// `SET SCHEMA new_schema`
1037    SetSchema { schema_name: ObjectName },
1038    /// `SET ( options )`
1039    Set {
1040        /// List of operator options to set
1041        options: Vec<OperatorOption>,
1042    },
1043}
1044
1045/// Option for `ALTER OPERATOR SET` operation
1046#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1047#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1048#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1049pub enum OperatorOption {
1050    /// `RESTRICT = { res_proc | NONE }`
1051    Restrict(Option<ObjectName>),
1052    /// `JOIN = { join_proc | NONE }`
1053    Join(Option<ObjectName>),
1054    /// `COMMUTATOR = com_op`
1055    Commutator(ObjectName),
1056    /// `NEGATOR = neg_op`
1057    Negator(ObjectName),
1058    /// `HASHES`
1059    Hashes,
1060    /// `MERGES`
1061    Merges,
1062}
1063
1064impl fmt::Display for AlterOperator {
1065    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1066        write!(f, "ALTER OPERATOR {} (", self.name)?;
1067        if let Some(left_type) = &self.left_type {
1068            write!(f, "{}", left_type)?;
1069        } else {
1070            write!(f, "NONE")?;
1071        }
1072        write!(f, ", {}) {}", self.right_type, self.operation)
1073    }
1074}
1075
1076impl fmt::Display for AlterOperatorOperation {
1077    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1078        match self {
1079            Self::OwnerTo(owner) => write!(f, "OWNER TO {}", owner),
1080            Self::SetSchema { schema_name } => write!(f, "SET SCHEMA {}", schema_name),
1081            Self::Set { options } => {
1082                write!(f, "SET (")?;
1083                for (i, option) in options.iter().enumerate() {
1084                    if i > 0 {
1085                        write!(f, ", ")?;
1086                    }
1087                    write!(f, "{}", option)?;
1088                }
1089                write!(f, ")")
1090            }
1091        }
1092    }
1093}
1094
1095impl fmt::Display for OperatorOption {
1096    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1097        match self {
1098            Self::Restrict(Some(proc_name)) => write!(f, "RESTRICT = {}", proc_name),
1099            Self::Restrict(None) => write!(f, "RESTRICT = NONE"),
1100            Self::Join(Some(proc_name)) => write!(f, "JOIN = {}", proc_name),
1101            Self::Join(None) => write!(f, "JOIN = NONE"),
1102            Self::Commutator(op_name) => write!(f, "COMMUTATOR = {}", op_name),
1103            Self::Negator(op_name) => write!(f, "NEGATOR = {}", op_name),
1104            Self::Hashes => write!(f, "HASHES"),
1105            Self::Merges => write!(f, "MERGES"),
1106        }
1107    }
1108}
1109
1110/// An `ALTER COLUMN` (`Statement::AlterTable`) operation
1111#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1112#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1113#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1114pub enum AlterColumnOperation {
1115    /// `SET NOT NULL`
1116    SetNotNull,
1117    /// `DROP NOT NULL`
1118    DropNotNull,
1119    /// `SET DEFAULT <expr>`
1120    SetDefault { value: Expr },
1121    /// `DROP DEFAULT`
1122    DropDefault,
1123    /// `[SET DATA] TYPE <data_type> [USING <expr>]`
1124    SetDataType {
1125        data_type: DataType,
1126        /// PostgreSQL specific
1127        using: Option<Expr>,
1128        /// Set to true if the statement includes the `SET DATA TYPE` keywords
1129        had_set: bool,
1130    },
1131
1132    /// `ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]`
1133    ///
1134    /// Note: this is a PostgreSQL-specific operation.
1135    AddGenerated {
1136        generated_as: Option<GeneratedAs>,
1137        sequence_options: Option<Vec<SequenceOptions>>,
1138    },
1139}
1140
1141impl fmt::Display for AlterColumnOperation {
1142    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1143        match self {
1144            AlterColumnOperation::SetNotNull => write!(f, "SET NOT NULL",),
1145            AlterColumnOperation::DropNotNull => write!(f, "DROP NOT NULL",),
1146            AlterColumnOperation::SetDefault { value } => {
1147                write!(f, "SET DEFAULT {value}")
1148            }
1149            AlterColumnOperation::DropDefault => {
1150                write!(f, "DROP DEFAULT")
1151            }
1152            AlterColumnOperation::SetDataType {
1153                data_type,
1154                using,
1155                had_set,
1156            } => {
1157                if *had_set {
1158                    write!(f, "SET DATA ")?;
1159                }
1160                write!(f, "TYPE {data_type}")?;
1161                if let Some(expr) = using {
1162                    write!(f, " USING {expr}")?;
1163                }
1164                Ok(())
1165            }
1166            AlterColumnOperation::AddGenerated {
1167                generated_as,
1168                sequence_options,
1169            } => {
1170                let generated_as = match generated_as {
1171                    Some(GeneratedAs::Always) => " ALWAYS",
1172                    Some(GeneratedAs::ByDefault) => " BY DEFAULT",
1173                    _ => "",
1174                };
1175
1176                write!(f, "ADD GENERATED{generated_as} AS IDENTITY",)?;
1177                if let Some(options) = sequence_options {
1178                    write!(f, " (")?;
1179
1180                    for sequence_option in options {
1181                        write!(f, "{sequence_option}")?;
1182                    }
1183
1184                    write!(f, " )")?;
1185                }
1186                Ok(())
1187            }
1188        }
1189    }
1190}
1191
1192/// Representation whether a definition can can contains the KEY or INDEX keywords with the same
1193/// meaning.
1194///
1195/// This enum initially is directed to `FULLTEXT`,`SPATIAL`, and `UNIQUE` indexes on create table
1196/// statements of `MySQL` [(1)].
1197///
1198/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1199#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1200#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1201#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1202pub enum KeyOrIndexDisplay {
1203    /// Nothing to display
1204    None,
1205    /// Display the KEY keyword
1206    Key,
1207    /// Display the INDEX keyword
1208    Index,
1209}
1210
1211impl KeyOrIndexDisplay {
1212    pub fn is_none(self) -> bool {
1213        matches!(self, Self::None)
1214    }
1215}
1216
1217impl fmt::Display for KeyOrIndexDisplay {
1218    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1219        let left_space = matches!(f.align(), Some(fmt::Alignment::Right));
1220
1221        if left_space && !self.is_none() {
1222            f.write_char(' ')?
1223        }
1224
1225        match self {
1226            KeyOrIndexDisplay::None => {
1227                write!(f, "")
1228            }
1229            KeyOrIndexDisplay::Key => {
1230                write!(f, "KEY")
1231            }
1232            KeyOrIndexDisplay::Index => {
1233                write!(f, "INDEX")
1234            }
1235        }
1236    }
1237}
1238
1239/// Indexing method used by that index.
1240///
1241/// This structure isn't present on ANSI, but is found at least in [`MySQL` CREATE TABLE][1],
1242/// [`MySQL` CREATE INDEX][2], and [Postgresql CREATE INDEX][3] statements.
1243///
1244/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1245/// [2]: https://dev.mysql.com/doc/refman/8.0/en/create-index.html
1246/// [3]: https://www.postgresql.org/docs/14/sql-createindex.html
1247#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1248#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1249#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1250pub enum IndexType {
1251    BTree,
1252    Hash,
1253    GIN,
1254    GiST,
1255    SPGiST,
1256    BRIN,
1257    Bloom,
1258    /// Users may define their own index types, which would
1259    /// not be covered by the above variants.
1260    Custom(Ident),
1261}
1262
1263impl fmt::Display for IndexType {
1264    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1265        match self {
1266            Self::BTree => write!(f, "BTREE"),
1267            Self::Hash => write!(f, "HASH"),
1268            Self::GIN => write!(f, "GIN"),
1269            Self::GiST => write!(f, "GIST"),
1270            Self::SPGiST => write!(f, "SPGIST"),
1271            Self::BRIN => write!(f, "BRIN"),
1272            Self::Bloom => write!(f, "BLOOM"),
1273            Self::Custom(name) => write!(f, "{name}"),
1274        }
1275    }
1276}
1277
1278/// MySQL index option, used in [`CREATE TABLE`], [`CREATE INDEX`], and [`ALTER TABLE`].
1279///
1280/// [`CREATE TABLE`]: https://dev.mysql.com/doc/refman/8.4/en/create-table.html
1281/// [`CREATE INDEX`]: https://dev.mysql.com/doc/refman/8.4/en/create-index.html
1282/// [`ALTER TABLE`]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
1283#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1284#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1285#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1286pub enum IndexOption {
1287    /// `USING { BTREE | HASH }`: Index type to use for the index.
1288    ///
1289    /// Note that we permissively parse non-MySQL index types, like `GIN`.
1290    Using(IndexType),
1291    /// `COMMENT 'string'`: Specifies a comment for the index.
1292    Comment(String),
1293}
1294
1295impl fmt::Display for IndexOption {
1296    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1297        match self {
1298            Self::Using(index_type) => write!(f, "USING {index_type}"),
1299            Self::Comment(s) => write!(f, "COMMENT '{s}'"),
1300        }
1301    }
1302}
1303
1304/// [PostgreSQL] unique index nulls handling option: `[ NULLS [ NOT ] DISTINCT ]`
1305///
1306/// [PostgreSQL]: https://www.postgresql.org/docs/17/sql-altertable.html
1307#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1308#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1309#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1310pub enum NullsDistinctOption {
1311    /// Not specified
1312    None,
1313    /// NULLS DISTINCT
1314    Distinct,
1315    /// NULLS NOT DISTINCT
1316    NotDistinct,
1317}
1318
1319impl fmt::Display for NullsDistinctOption {
1320    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1321        match self {
1322            Self::None => Ok(()),
1323            Self::Distinct => write!(f, " NULLS DISTINCT"),
1324            Self::NotDistinct => write!(f, " NULLS NOT DISTINCT"),
1325        }
1326    }
1327}
1328
1329#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1330#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1331#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1332pub struct ProcedureParam {
1333    pub name: Ident,
1334    pub data_type: DataType,
1335    pub mode: Option<ArgMode>,
1336    pub default: Option<Expr>,
1337}
1338
1339impl fmt::Display for ProcedureParam {
1340    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1341        if let Some(mode) = &self.mode {
1342            if let Some(default) = &self.default {
1343                write!(f, "{mode} {} {} = {}", self.name, self.data_type, default)
1344            } else {
1345                write!(f, "{mode} {} {}", self.name, self.data_type)
1346            }
1347        } else if let Some(default) = &self.default {
1348            write!(f, "{} {} = {}", self.name, self.data_type, default)
1349        } else {
1350            write!(f, "{} {}", self.name, self.data_type)
1351        }
1352    }
1353}
1354
1355/// SQL column definition
1356#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1357#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1358#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1359pub struct ColumnDef {
1360    pub name: Ident,
1361    pub data_type: DataType,
1362    pub options: Vec<ColumnOptionDef>,
1363}
1364
1365impl fmt::Display for ColumnDef {
1366    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1367        if self.data_type == DataType::Unspecified {
1368            write!(f, "{}", self.name)?;
1369        } else {
1370            write!(f, "{} {}", self.name, self.data_type)?;
1371        }
1372        for option in &self.options {
1373            write!(f, " {option}")?;
1374        }
1375        Ok(())
1376    }
1377}
1378
1379/// Column definition specified in a `CREATE VIEW` statement.
1380///
1381/// Syntax
1382/// ```markdown
1383/// <name> [data_type][OPTIONS(option, ...)]
1384///
1385/// option: <name> = <value>
1386/// ```
1387///
1388/// Examples:
1389/// ```sql
1390/// name
1391/// age OPTIONS(description = "age column", tag = "prod")
1392/// amount COMMENT 'The total amount for the order line'
1393/// created_at DateTime64
1394/// ```
1395#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1396#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1397#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1398pub struct ViewColumnDef {
1399    pub name: Ident,
1400    pub data_type: Option<DataType>,
1401    pub options: Option<ColumnOptions>,
1402}
1403
1404#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1405#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1406#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1407pub enum ColumnOptions {
1408    CommaSeparated(Vec<ColumnOption>),
1409    SpaceSeparated(Vec<ColumnOption>),
1410}
1411
1412impl ColumnOptions {
1413    pub fn as_slice(&self) -> &[ColumnOption] {
1414        match self {
1415            ColumnOptions::CommaSeparated(options) => options.as_slice(),
1416            ColumnOptions::SpaceSeparated(options) => options.as_slice(),
1417        }
1418    }
1419}
1420
1421impl fmt::Display for ViewColumnDef {
1422    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1423        write!(f, "{}", self.name)?;
1424        if let Some(data_type) = self.data_type.as_ref() {
1425            write!(f, " {data_type}")?;
1426        }
1427        if let Some(options) = self.options.as_ref() {
1428            match options {
1429                ColumnOptions::CommaSeparated(column_options) => {
1430                    write!(f, " {}", display_comma_separated(column_options.as_slice()))?;
1431                }
1432                ColumnOptions::SpaceSeparated(column_options) => {
1433                    write!(f, " {}", display_separated(column_options.as_slice(), " "))?
1434                }
1435            }
1436        }
1437        Ok(())
1438    }
1439}
1440
1441/// An optionally-named `ColumnOption`: `[ CONSTRAINT <name> ] <column-option>`.
1442///
1443/// Note that implementations are substantially more permissive than the ANSI
1444/// specification on what order column options can be presented in, and whether
1445/// they are allowed to be named. The specification distinguishes between
1446/// constraints (NOT NULL, UNIQUE, PRIMARY KEY, and CHECK), which can be named
1447/// and can appear in any order, and other options (DEFAULT, GENERATED), which
1448/// cannot be named and must appear in a fixed order. `PostgreSQL`, however,
1449/// allows preceding any option with `CONSTRAINT <name>`, even those that are
1450/// not really constraints, like NULL and DEFAULT. MSSQL is less permissive,
1451/// allowing DEFAULT, UNIQUE, PRIMARY KEY and CHECK to be named, but not NULL or
1452/// NOT NULL constraints (the last of which is in violation of the spec).
1453///
1454/// For maximum flexibility, we don't distinguish between constraint and
1455/// non-constraint options, lumping them all together under the umbrella of
1456/// "column options," and we allow any column option to be named.
1457#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1458#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1459#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1460pub struct ColumnOptionDef {
1461    pub name: Option<Ident>,
1462    pub option: ColumnOption,
1463}
1464
1465impl fmt::Display for ColumnOptionDef {
1466    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1467        write!(f, "{}{}", display_constraint_name(&self.name), self.option)
1468    }
1469}
1470
1471/// Identity is a column option for defining an identity or autoincrement column in a `CREATE TABLE` statement.
1472/// Syntax
1473/// ```sql
1474/// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1475/// ```
1476/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1477/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1478#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1479#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1480#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1481pub enum IdentityPropertyKind {
1482    /// An identity property declared via the `AUTOINCREMENT` key word
1483    /// Example:
1484    /// ```sql
1485    ///  AUTOINCREMENT(100, 1) NOORDER
1486    ///  AUTOINCREMENT START 100 INCREMENT 1 ORDER
1487    /// ```
1488    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1489    Autoincrement(IdentityProperty),
1490    /// An identity property declared via the `IDENTITY` key word
1491    /// Example, [MS SQL Server] or [Snowflake]:
1492    /// ```sql
1493    ///  IDENTITY(100, 1)
1494    /// ```
1495    /// [Snowflake]
1496    /// ```sql
1497    ///  IDENTITY(100, 1) ORDER
1498    ///  IDENTITY START 100 INCREMENT 1 NOORDER
1499    /// ```
1500    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1501    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1502    Identity(IdentityProperty),
1503}
1504
1505impl fmt::Display for IdentityPropertyKind {
1506    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1507        let (command, property) = match self {
1508            IdentityPropertyKind::Identity(property) => ("IDENTITY", property),
1509            IdentityPropertyKind::Autoincrement(property) => ("AUTOINCREMENT", property),
1510        };
1511        write!(f, "{command}")?;
1512        if let Some(parameters) = &property.parameters {
1513            write!(f, "{parameters}")?;
1514        }
1515        if let Some(order) = &property.order {
1516            write!(f, "{order}")?;
1517        }
1518        Ok(())
1519    }
1520}
1521
1522#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1523#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1524#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1525pub struct IdentityProperty {
1526    pub parameters: Option<IdentityPropertyFormatKind>,
1527    pub order: Option<IdentityPropertyOrder>,
1528}
1529
1530/// A format of parameters of identity column.
1531///
1532/// It is [Snowflake] specific.
1533/// Syntax
1534/// ```sql
1535/// (seed , increment) | START num INCREMENT num
1536/// ```
1537/// [MS SQL Server] uses one way of representing these parameters.
1538/// Syntax
1539/// ```sql
1540/// (seed , increment)
1541/// ```
1542/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1543/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1544#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1545#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1546#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1547pub enum IdentityPropertyFormatKind {
1548    /// A parameters of identity column declared like parameters of function call
1549    /// Example:
1550    /// ```sql
1551    ///  (100, 1)
1552    /// ```
1553    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1554    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1555    FunctionCall(IdentityParameters),
1556    /// A parameters of identity column declared with keywords `START` and `INCREMENT`
1557    /// Example:
1558    /// ```sql
1559    ///  START 100 INCREMENT 1
1560    /// ```
1561    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1562    StartAndIncrement(IdentityParameters),
1563}
1564
1565impl fmt::Display for IdentityPropertyFormatKind {
1566    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1567        match self {
1568            IdentityPropertyFormatKind::FunctionCall(parameters) => {
1569                write!(f, "({}, {})", parameters.seed, parameters.increment)
1570            }
1571            IdentityPropertyFormatKind::StartAndIncrement(parameters) => {
1572                write!(
1573                    f,
1574                    " START {} INCREMENT {}",
1575                    parameters.seed, parameters.increment
1576                )
1577            }
1578        }
1579    }
1580}
1581#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1582#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1583#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1584pub struct IdentityParameters {
1585    pub seed: Expr,
1586    pub increment: Expr,
1587}
1588
1589/// The identity column option specifies how values are generated for the auto-incremented column, either in increasing or decreasing order.
1590/// Syntax
1591/// ```sql
1592/// ORDER | NOORDER
1593/// ```
1594/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1595#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1596#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1597#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1598pub enum IdentityPropertyOrder {
1599    Order,
1600    NoOrder,
1601}
1602
1603impl fmt::Display for IdentityPropertyOrder {
1604    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1605        match self {
1606            IdentityPropertyOrder::Order => write!(f, " ORDER"),
1607            IdentityPropertyOrder::NoOrder => write!(f, " NOORDER"),
1608        }
1609    }
1610}
1611
1612/// Column policy that identify a security policy of access to a column.
1613/// Syntax
1614/// ```sql
1615/// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1616/// [ WITH ] PROJECTION POLICY <policy_name>
1617/// ```
1618/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1619#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1620#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1621#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1622pub enum ColumnPolicy {
1623    MaskingPolicy(ColumnPolicyProperty),
1624    ProjectionPolicy(ColumnPolicyProperty),
1625}
1626
1627impl fmt::Display for ColumnPolicy {
1628    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1629        let (command, property) = match self {
1630            ColumnPolicy::MaskingPolicy(property) => ("MASKING POLICY", property),
1631            ColumnPolicy::ProjectionPolicy(property) => ("PROJECTION POLICY", property),
1632        };
1633        if property.with {
1634            write!(f, "WITH ")?;
1635        }
1636        write!(f, "{command} {}", property.policy_name)?;
1637        if let Some(using_columns) = &property.using_columns {
1638            write!(f, " USING ({})", display_comma_separated(using_columns))?;
1639        }
1640        Ok(())
1641    }
1642}
1643
1644#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1645#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1646#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1647pub struct ColumnPolicyProperty {
1648    /// This flag indicates that the column policy option is declared using the `WITH` prefix.
1649    /// Example
1650    /// ```sql
1651    /// WITH PROJECTION POLICY sample_policy
1652    /// ```
1653    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1654    pub with: bool,
1655    pub policy_name: ObjectName,
1656    pub using_columns: Option<Vec<Ident>>,
1657}
1658
1659/// Tags option of column
1660/// Syntax
1661/// ```sql
1662/// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1663/// ```
1664/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1665#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1666#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1667#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1668pub struct TagsColumnOption {
1669    /// This flag indicates that the tags option is declared using the `WITH` prefix.
1670    /// Example:
1671    /// ```sql
1672    /// WITH TAG (A = 'Tag A')
1673    /// ```
1674    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1675    pub with: bool,
1676    pub tags: Vec<Tag>,
1677}
1678
1679impl fmt::Display for TagsColumnOption {
1680    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1681        if self.with {
1682            write!(f, "WITH ")?;
1683        }
1684        write!(f, "TAG ({})", display_comma_separated(&self.tags))?;
1685        Ok(())
1686    }
1687}
1688
1689/// `ColumnOption`s are modifiers that follow a column definition in a `CREATE
1690/// TABLE` statement.
1691#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1692#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1693#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1694pub enum ColumnOption {
1695    /// `NULL`
1696    Null,
1697    /// `NOT NULL`
1698    NotNull,
1699    /// `DEFAULT <restricted-expr>`
1700    Default(Expr),
1701
1702    /// `MATERIALIZE <expr>`
1703    /// Syntax: `b INT MATERIALIZE (a + 1)`
1704    ///
1705    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1706    Materialized(Expr),
1707    /// `EPHEMERAL [<expr>]`
1708    ///
1709    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1710    Ephemeral(Option<Expr>),
1711    /// `ALIAS <expr>`
1712    ///
1713    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1714    Alias(Expr),
1715
1716    /// `PRIMARY KEY [<constraint_characteristics>]`
1717    PrimaryKey(PrimaryKeyConstraint),
1718    /// `UNIQUE [<constraint_characteristics>]`
1719    Unique(UniqueConstraint),
1720    /// A referential integrity constraint (`REFERENCES <foreign_table> (<referred_columns>)
1721    /// [ MATCH { FULL | PARTIAL | SIMPLE } ]
1722    /// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
1723    ///   [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
1724    /// }         
1725    /// [<constraint_characteristics>]
1726    /// `).
1727    ForeignKey(ForeignKeyConstraint),
1728    /// `CHECK (<expr>)`
1729    Check(CheckConstraint),
1730    /// Dialect-specific options, such as:
1731    /// - MySQL's `AUTO_INCREMENT` or SQLite's `AUTOINCREMENT`
1732    /// - ...
1733    DialectSpecific(Vec<Token>),
1734    CharacterSet(ObjectName),
1735    Collation(ObjectName),
1736    Comment(String),
1737    OnUpdate(Expr),
1738    /// `Generated`s are modifiers that follow a column definition in a `CREATE
1739    /// TABLE` statement.
1740    Generated {
1741        generated_as: GeneratedAs,
1742        sequence_options: Option<Vec<SequenceOptions>>,
1743        generation_expr: Option<Expr>,
1744        generation_expr_mode: Option<GeneratedExpressionMode>,
1745        /// false if 'GENERATED ALWAYS' is skipped (option starts with AS)
1746        generated_keyword: bool,
1747    },
1748    /// BigQuery specific: Explicit column options in a view [1] or table [2]
1749    /// Syntax
1750    /// ```sql
1751    /// OPTIONS(description="field desc")
1752    /// ```
1753    /// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#view_column_option_list
1754    /// [2]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#column_option_list
1755    Options(Vec<SqlOption>),
1756    /// Creates an identity or an autoincrement column in a table.
1757    /// Syntax
1758    /// ```sql
1759    /// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1760    /// ```
1761    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1762    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1763    Identity(IdentityPropertyKind),
1764    /// SQLite specific: ON CONFLICT option on column definition
1765    /// <https://www.sqlite.org/lang_conflict.html>
1766    OnConflict(Keyword),
1767    /// Snowflake specific: an option of specifying security masking or projection policy to set on 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    Policy(ColumnPolicy),
1775    /// Snowflake specific: Specifies the tag name and the tag string value.
1776    /// Syntax:
1777    /// ```sql
1778    /// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1779    /// ```
1780    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1781    Tags(TagsColumnOption),
1782    /// MySQL specific: Spatial reference identifier
1783    /// Syntax:
1784    /// ```sql
1785    /// CREATE TABLE geom (g GEOMETRY NOT NULL SRID 4326);
1786    /// ```
1787    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/creating-spatial-indexes.html
1788    Srid(Box<Expr>),
1789    /// MySQL specific: Column is invisible via SELECT *
1790    /// Syntax:
1791    /// ```sql
1792    /// CREATE TABLE t (foo INT, bar INT INVISIBLE);
1793    /// ```
1794    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/invisible-columns.html
1795    Invisible,
1796}
1797
1798impl From<UniqueConstraint> for ColumnOption {
1799    fn from(c: UniqueConstraint) -> Self {
1800        ColumnOption::Unique(c)
1801    }
1802}
1803
1804impl From<PrimaryKeyConstraint> for ColumnOption {
1805    fn from(c: PrimaryKeyConstraint) -> Self {
1806        ColumnOption::PrimaryKey(c)
1807    }
1808}
1809
1810impl From<CheckConstraint> for ColumnOption {
1811    fn from(c: CheckConstraint) -> Self {
1812        ColumnOption::Check(c)
1813    }
1814}
1815impl From<ForeignKeyConstraint> for ColumnOption {
1816    fn from(fk: ForeignKeyConstraint) -> Self {
1817        ColumnOption::ForeignKey(fk)
1818    }
1819}
1820
1821impl fmt::Display for ColumnOption {
1822    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1823        use ColumnOption::*;
1824        match self {
1825            Null => write!(f, "NULL"),
1826            NotNull => write!(f, "NOT NULL"),
1827            Default(expr) => write!(f, "DEFAULT {expr}"),
1828            Materialized(expr) => write!(f, "MATERIALIZED {expr}"),
1829            Ephemeral(expr) => {
1830                if let Some(e) = expr {
1831                    write!(f, "EPHEMERAL {e}")
1832                } else {
1833                    write!(f, "EPHEMERAL")
1834                }
1835            }
1836            Alias(expr) => write!(f, "ALIAS {expr}"),
1837            PrimaryKey(constraint) => {
1838                write!(f, "PRIMARY KEY")?;
1839                if let Some(characteristics) = &constraint.characteristics {
1840                    write!(f, " {characteristics}")?;
1841                }
1842                Ok(())
1843            }
1844            Unique(constraint) => {
1845                write!(f, "UNIQUE")?;
1846                if let Some(characteristics) = &constraint.characteristics {
1847                    write!(f, " {characteristics}")?;
1848                }
1849                Ok(())
1850            }
1851            ForeignKey(constraint) => {
1852                write!(f, "REFERENCES {}", constraint.foreign_table)?;
1853                if !constraint.referred_columns.is_empty() {
1854                    write!(
1855                        f,
1856                        " ({})",
1857                        display_comma_separated(&constraint.referred_columns)
1858                    )?;
1859                }
1860                if let Some(match_kind) = &constraint.match_kind {
1861                    write!(f, " {match_kind}")?;
1862                }
1863                if let Some(action) = &constraint.on_delete {
1864                    write!(f, " ON DELETE {action}")?;
1865                }
1866                if let Some(action) = &constraint.on_update {
1867                    write!(f, " ON UPDATE {action}")?;
1868                }
1869                if let Some(characteristics) = &constraint.characteristics {
1870                    write!(f, " {characteristics}")?;
1871                }
1872                Ok(())
1873            }
1874            Check(constraint) => write!(f, "{constraint}"),
1875            DialectSpecific(val) => write!(f, "{}", display_separated(val, " ")),
1876            CharacterSet(n) => write!(f, "CHARACTER SET {n}"),
1877            Collation(n) => write!(f, "COLLATE {n}"),
1878            Comment(v) => write!(f, "COMMENT '{}'", escape_single_quote_string(v)),
1879            OnUpdate(expr) => write!(f, "ON UPDATE {expr}"),
1880            Generated {
1881                generated_as,
1882                sequence_options,
1883                generation_expr,
1884                generation_expr_mode,
1885                generated_keyword,
1886            } => {
1887                if let Some(expr) = generation_expr {
1888                    let modifier = match generation_expr_mode {
1889                        None => "",
1890                        Some(GeneratedExpressionMode::Virtual) => " VIRTUAL",
1891                        Some(GeneratedExpressionMode::Stored) => " STORED",
1892                    };
1893                    if *generated_keyword {
1894                        write!(f, "GENERATED ALWAYS AS ({expr}){modifier}")?;
1895                    } else {
1896                        write!(f, "AS ({expr}){modifier}")?;
1897                    }
1898                    Ok(())
1899                } else {
1900                    // Like Postgres - generated from sequence
1901                    let when = match generated_as {
1902                        GeneratedAs::Always => "ALWAYS",
1903                        GeneratedAs::ByDefault => "BY DEFAULT",
1904                        // ExpStored goes with an expression, handled above
1905                        GeneratedAs::ExpStored => "",
1906                    };
1907                    write!(f, "GENERATED {when} AS IDENTITY")?;
1908                    if sequence_options.is_some() {
1909                        let so = sequence_options.as_ref().unwrap();
1910                        if !so.is_empty() {
1911                            write!(f, " (")?;
1912                        }
1913                        for sequence_option in so {
1914                            write!(f, "{sequence_option}")?;
1915                        }
1916                        if !so.is_empty() {
1917                            write!(f, " )")?;
1918                        }
1919                    }
1920                    Ok(())
1921                }
1922            }
1923            Options(options) => {
1924                write!(f, "OPTIONS({})", display_comma_separated(options))
1925            }
1926            Identity(parameters) => {
1927                write!(f, "{parameters}")
1928            }
1929            OnConflict(keyword) => {
1930                write!(f, "ON CONFLICT {keyword:?}")?;
1931                Ok(())
1932            }
1933            Policy(parameters) => {
1934                write!(f, "{parameters}")
1935            }
1936            Tags(tags) => {
1937                write!(f, "{tags}")
1938            }
1939            Srid(srid) => {
1940                write!(f, "SRID {srid}")
1941            }
1942            Invisible => {
1943                write!(f, "INVISIBLE")
1944            }
1945        }
1946    }
1947}
1948
1949/// `GeneratedAs`s are modifiers that follow a column option in a `generated`.
1950/// 'ExpStored' is used for a column generated from an expression and stored.
1951#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1952#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1953#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1954pub enum GeneratedAs {
1955    Always,
1956    ByDefault,
1957    ExpStored,
1958}
1959
1960/// `GeneratedExpressionMode`s are modifiers that follow an expression in a `generated`.
1961/// No modifier is typically the same as Virtual.
1962#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1963#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1964#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1965pub enum GeneratedExpressionMode {
1966    Virtual,
1967    Stored,
1968}
1969
1970#[must_use]
1971pub(crate) fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
1972    struct ConstraintName<'a>(&'a Option<Ident>);
1973    impl fmt::Display for ConstraintName<'_> {
1974        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1975            if let Some(name) = self.0 {
1976                write!(f, "CONSTRAINT {name} ")?;
1977            }
1978            Ok(())
1979        }
1980    }
1981    ConstraintName(name)
1982}
1983
1984/// If `option` is
1985/// * `Some(inner)` => create display struct for `"{prefix}{inner}{postfix}"`
1986/// * `_` => do nothing
1987#[must_use]
1988pub(crate) fn display_option<'a, T: fmt::Display>(
1989    prefix: &'a str,
1990    postfix: &'a str,
1991    option: &'a Option<T>,
1992) -> impl fmt::Display + 'a {
1993    struct OptionDisplay<'a, T>(&'a str, &'a str, &'a Option<T>);
1994    impl<T: fmt::Display> fmt::Display for OptionDisplay<'_, T> {
1995        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1996            if let Some(inner) = self.2 {
1997                let (prefix, postfix) = (self.0, self.1);
1998                write!(f, "{prefix}{inner}{postfix}")?;
1999            }
2000            Ok(())
2001        }
2002    }
2003    OptionDisplay(prefix, postfix, option)
2004}
2005
2006/// If `option` is
2007/// * `Some(inner)` => create display struct for `" {inner}"`
2008/// * `_` => do nothing
2009#[must_use]
2010pub(crate) fn display_option_spaced<T: fmt::Display>(option: &Option<T>) -> impl fmt::Display + '_ {
2011    display_option(" ", "", option)
2012}
2013
2014/// `<constraint_characteristics> = [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ]`
2015///
2016/// Used in UNIQUE and foreign key constraints. The individual settings may occur in any order.
2017#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Default, Eq, Ord, Hash)]
2018#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2019#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2020pub struct ConstraintCharacteristics {
2021    /// `[ DEFERRABLE | NOT DEFERRABLE ]`
2022    pub deferrable: Option<bool>,
2023    /// `[ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]`
2024    pub initially: Option<DeferrableInitial>,
2025    /// `[ ENFORCED | NOT ENFORCED ]`
2026    pub enforced: Option<bool>,
2027}
2028
2029#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2030#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2031#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2032pub enum DeferrableInitial {
2033    /// `INITIALLY IMMEDIATE`
2034    Immediate,
2035    /// `INITIALLY DEFERRED`
2036    Deferred,
2037}
2038
2039impl ConstraintCharacteristics {
2040    fn deferrable_text(&self) -> Option<&'static str> {
2041        self.deferrable.map(|deferrable| {
2042            if deferrable {
2043                "DEFERRABLE"
2044            } else {
2045                "NOT DEFERRABLE"
2046            }
2047        })
2048    }
2049
2050    fn initially_immediate_text(&self) -> Option<&'static str> {
2051        self.initially
2052            .map(|initially_immediate| match initially_immediate {
2053                DeferrableInitial::Immediate => "INITIALLY IMMEDIATE",
2054                DeferrableInitial::Deferred => "INITIALLY DEFERRED",
2055            })
2056    }
2057
2058    fn enforced_text(&self) -> Option<&'static str> {
2059        self.enforced.map(
2060            |enforced| {
2061                if enforced {
2062                    "ENFORCED"
2063                } else {
2064                    "NOT ENFORCED"
2065                }
2066            },
2067        )
2068    }
2069}
2070
2071impl fmt::Display for ConstraintCharacteristics {
2072    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2073        let deferrable = self.deferrable_text();
2074        let initially_immediate = self.initially_immediate_text();
2075        let enforced = self.enforced_text();
2076
2077        match (deferrable, initially_immediate, enforced) {
2078            (None, None, None) => Ok(()),
2079            (None, None, Some(enforced)) => write!(f, "{enforced}"),
2080            (None, Some(initial), None) => write!(f, "{initial}"),
2081            (None, Some(initial), Some(enforced)) => write!(f, "{initial} {enforced}"),
2082            (Some(deferrable), None, None) => write!(f, "{deferrable}"),
2083            (Some(deferrable), None, Some(enforced)) => write!(f, "{deferrable} {enforced}"),
2084            (Some(deferrable), Some(initial), None) => write!(f, "{deferrable} {initial}"),
2085            (Some(deferrable), Some(initial), Some(enforced)) => {
2086                write!(f, "{deferrable} {initial} {enforced}")
2087            }
2088        }
2089    }
2090}
2091
2092/// `<referential_action> =
2093/// { RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT }`
2094///
2095/// Used in foreign key constraints in `ON UPDATE` and `ON DELETE` options.
2096#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2097#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2098#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2099pub enum ReferentialAction {
2100    Restrict,
2101    Cascade,
2102    SetNull,
2103    NoAction,
2104    SetDefault,
2105}
2106
2107impl fmt::Display for ReferentialAction {
2108    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2109        f.write_str(match self {
2110            ReferentialAction::Restrict => "RESTRICT",
2111            ReferentialAction::Cascade => "CASCADE",
2112            ReferentialAction::SetNull => "SET NULL",
2113            ReferentialAction::NoAction => "NO ACTION",
2114            ReferentialAction::SetDefault => "SET DEFAULT",
2115        })
2116    }
2117}
2118
2119/// `<drop behavior> ::= CASCADE | RESTRICT`.
2120///
2121/// Used in `DROP` statements.
2122#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2123#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2124#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2125pub enum DropBehavior {
2126    Restrict,
2127    Cascade,
2128}
2129
2130impl fmt::Display for DropBehavior {
2131    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2132        f.write_str(match self {
2133            DropBehavior::Restrict => "RESTRICT",
2134            DropBehavior::Cascade => "CASCADE",
2135        })
2136    }
2137}
2138
2139/// SQL user defined type definition
2140#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2141#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2142#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2143pub enum UserDefinedTypeRepresentation {
2144    /// Composite type: `CREATE TYPE name AS (attributes)`
2145    Composite {
2146        attributes: Vec<UserDefinedTypeCompositeAttributeDef>,
2147    },
2148    /// Enum type: `CREATE TYPE name AS ENUM (labels)`
2149    ///
2150    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2151    Enum { labels: Vec<Ident> },
2152    /// Range type: `CREATE TYPE name AS RANGE (options)`
2153    ///
2154    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2155    Range {
2156        options: Vec<UserDefinedTypeRangeOption>,
2157    },
2158    /// Base type (SQL definition): `CREATE TYPE name (options)`
2159    ///
2160    /// Note the lack of `AS` keyword
2161    ///
2162    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2163    SqlDefinition {
2164        options: Vec<UserDefinedTypeSqlDefinitionOption>,
2165    },
2166}
2167
2168impl fmt::Display for UserDefinedTypeRepresentation {
2169    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2170        match self {
2171            Self::Composite { attributes } => {
2172                write!(f, "AS ({})", display_comma_separated(attributes))
2173            }
2174            Self::Enum { labels } => {
2175                write!(f, "AS ENUM ({})", display_comma_separated(labels))
2176            }
2177            Self::Range { options } => {
2178                write!(f, "AS RANGE ({})", display_comma_separated(options))
2179            }
2180            Self::SqlDefinition { options } => {
2181                write!(f, "({})", display_comma_separated(options))
2182            }
2183        }
2184    }
2185}
2186
2187/// SQL user defined type attribute definition
2188#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2189#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2190#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2191pub struct UserDefinedTypeCompositeAttributeDef {
2192    pub name: Ident,
2193    pub data_type: DataType,
2194    pub collation: Option<ObjectName>,
2195}
2196
2197impl fmt::Display for UserDefinedTypeCompositeAttributeDef {
2198    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2199        write!(f, "{} {}", self.name, self.data_type)?;
2200        if let Some(collation) = &self.collation {
2201            write!(f, " COLLATE {collation}")?;
2202        }
2203        Ok(())
2204    }
2205}
2206
2207/// Internal length specification for PostgreSQL user-defined base types.
2208///
2209/// Specifies the internal length in bytes of the new type's internal representation.
2210/// The default assumption is that it is variable-length.
2211///
2212/// # PostgreSQL Documentation
2213/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2214///
2215/// # Examples
2216/// ```sql
2217/// CREATE TYPE mytype (
2218///     INPUT = in_func,
2219///     OUTPUT = out_func,
2220///     INTERNALLENGTH = 16  -- Fixed 16-byte length
2221/// );
2222///
2223/// CREATE TYPE mytype2 (
2224///     INPUT = in_func,
2225///     OUTPUT = out_func,
2226///     INTERNALLENGTH = VARIABLE  -- Variable length
2227/// );
2228/// ```
2229#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2230#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2231#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2232pub enum UserDefinedTypeInternalLength {
2233    /// Fixed internal length: `INTERNALLENGTH = <number>`
2234    Fixed(u64),
2235    /// Variable internal length: `INTERNALLENGTH = VARIABLE`
2236    Variable,
2237}
2238
2239impl fmt::Display for UserDefinedTypeInternalLength {
2240    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2241        match self {
2242            UserDefinedTypeInternalLength::Fixed(n) => write!(f, "{}", n),
2243            UserDefinedTypeInternalLength::Variable => write!(f, "VARIABLE"),
2244        }
2245    }
2246}
2247
2248/// Alignment specification for PostgreSQL user-defined base types.
2249///
2250/// Specifies the storage alignment requirement for values of the data type.
2251/// The allowed values equate to alignment on 1, 2, 4, or 8 byte boundaries.
2252/// Note that variable-length types must have an alignment of at least 4, since
2253/// they necessarily contain an int4 as their first component.
2254///
2255/// # PostgreSQL Documentation
2256/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2257///
2258/// # Examples
2259/// ```sql
2260/// CREATE TYPE mytype (
2261///     INPUT = in_func,
2262///     OUTPUT = out_func,
2263///     ALIGNMENT = int4  -- 4-byte alignment
2264/// );
2265/// ```
2266#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2267#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2268#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2269pub enum Alignment {
2270    /// Single-byte alignment: `ALIGNMENT = char`
2271    Char,
2272    /// 2-byte alignment: `ALIGNMENT = int2`
2273    Int2,
2274    /// 4-byte alignment: `ALIGNMENT = int4`
2275    Int4,
2276    /// 8-byte alignment: `ALIGNMENT = double`
2277    Double,
2278}
2279
2280impl fmt::Display for Alignment {
2281    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2282        match self {
2283            Alignment::Char => write!(f, "char"),
2284            Alignment::Int2 => write!(f, "int2"),
2285            Alignment::Int4 => write!(f, "int4"),
2286            Alignment::Double => write!(f, "double"),
2287        }
2288    }
2289}
2290
2291/// Storage specification for PostgreSQL user-defined base types.
2292///
2293/// Specifies the storage strategy for values of the data type:
2294/// - `plain`: Prevents compression and out-of-line storage (for fixed-length types)
2295/// - `external`: Allows out-of-line storage but not compression
2296/// - `extended`: Allows both compression and out-of-line storage (default for most types)
2297/// - `main`: Allows compression but discourages out-of-line storage
2298///
2299/// # PostgreSQL Documentation
2300/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2301///
2302/// # Examples
2303/// ```sql
2304/// CREATE TYPE mytype (
2305///     INPUT = in_func,
2306///     OUTPUT = out_func,
2307///     STORAGE = plain
2308/// );
2309/// ```
2310#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2311#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2312#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2313pub enum UserDefinedTypeStorage {
2314    /// No compression or out-of-line storage: `STORAGE = plain`
2315    Plain,
2316    /// Out-of-line storage allowed, no compression: `STORAGE = external`
2317    External,
2318    /// Both compression and out-of-line storage allowed: `STORAGE = extended`
2319    Extended,
2320    /// Compression allowed, out-of-line discouraged: `STORAGE = main`
2321    Main,
2322}
2323
2324impl fmt::Display for UserDefinedTypeStorage {
2325    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2326        match self {
2327            UserDefinedTypeStorage::Plain => write!(f, "plain"),
2328            UserDefinedTypeStorage::External => write!(f, "external"),
2329            UserDefinedTypeStorage::Extended => write!(f, "extended"),
2330            UserDefinedTypeStorage::Main => write!(f, "main"),
2331        }
2332    }
2333}
2334
2335/// Options for PostgreSQL `CREATE TYPE ... AS RANGE` statement.
2336///
2337/// Range types are data types representing a range of values of some element type
2338/// (called the range's subtype). These options configure the behavior of the range type.
2339///
2340/// # PostgreSQL Documentation
2341/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2342///
2343/// # Examples
2344/// ```sql
2345/// CREATE TYPE int4range AS RANGE (
2346///     SUBTYPE = int4,
2347///     SUBTYPE_OPCLASS = int4_ops,
2348///     CANONICAL = int4range_canonical,
2349///     SUBTYPE_DIFF = int4range_subdiff
2350/// );
2351/// ```
2352#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2353#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2354#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2355pub enum UserDefinedTypeRangeOption {
2356    /// The element type that the range type will represent: `SUBTYPE = subtype`
2357    Subtype(DataType),
2358    /// The operator class for the subtype: `SUBTYPE_OPCLASS = subtype_operator_class`
2359    SubtypeOpClass(ObjectName),
2360    /// Collation to use for ordering the subtype: `COLLATION = collation`
2361    Collation(ObjectName),
2362    /// Function to convert range values to canonical form: `CANONICAL = canonical_function`
2363    Canonical(ObjectName),
2364    /// Function to compute the difference between two subtype values: `SUBTYPE_DIFF = subtype_diff_function`
2365    SubtypeDiff(ObjectName),
2366    /// Name of the corresponding multirange type: `MULTIRANGE_TYPE_NAME = multirange_type_name`
2367    MultirangeTypeName(ObjectName),
2368}
2369
2370impl fmt::Display for UserDefinedTypeRangeOption {
2371    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2372        match self {
2373            UserDefinedTypeRangeOption::Subtype(dt) => write!(f, "SUBTYPE = {}", dt),
2374            UserDefinedTypeRangeOption::SubtypeOpClass(name) => {
2375                write!(f, "SUBTYPE_OPCLASS = {}", name)
2376            }
2377            UserDefinedTypeRangeOption::Collation(name) => write!(f, "COLLATION = {}", name),
2378            UserDefinedTypeRangeOption::Canonical(name) => write!(f, "CANONICAL = {}", name),
2379            UserDefinedTypeRangeOption::SubtypeDiff(name) => write!(f, "SUBTYPE_DIFF = {}", name),
2380            UserDefinedTypeRangeOption::MultirangeTypeName(name) => {
2381                write!(f, "MULTIRANGE_TYPE_NAME = {}", name)
2382            }
2383        }
2384    }
2385}
2386
2387/// Options for PostgreSQL `CREATE TYPE ... (<options>)` statement (base type definition).
2388///
2389/// Base types are the lowest-level data types in PostgreSQL. To define a new base type,
2390/// you must specify functions that convert it to and from text representation, and optionally
2391/// binary representation and other properties.
2392///
2393/// Note: This syntax uses parentheses directly after the type name, without the `AS` keyword.
2394///
2395/// # PostgreSQL Documentation
2396/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2397///
2398/// # Examples
2399/// ```sql
2400/// CREATE TYPE complex (
2401///     INPUT = complex_in,
2402///     OUTPUT = complex_out,
2403///     INTERNALLENGTH = 16,
2404///     ALIGNMENT = double
2405/// );
2406/// ```
2407#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2408#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2409#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2410pub enum UserDefinedTypeSqlDefinitionOption {
2411    /// Function to convert from external text representation to internal: `INPUT = input_function`
2412    Input(ObjectName),
2413    /// Function to convert from internal to external text representation: `OUTPUT = output_function`
2414    Output(ObjectName),
2415    /// Function to convert from external binary representation to internal: `RECEIVE = receive_function`
2416    Receive(ObjectName),
2417    /// Function to convert from internal to external binary representation: `SEND = send_function`
2418    Send(ObjectName),
2419    /// Function to convert type modifiers from text array to internal form: `TYPMOD_IN = type_modifier_input_function`
2420    TypmodIn(ObjectName),
2421    /// Function to convert type modifiers from internal to text form: `TYPMOD_OUT = type_modifier_output_function`
2422    TypmodOut(ObjectName),
2423    /// Function to compute statistics for the data type: `ANALYZE = analyze_function`
2424    Analyze(ObjectName),
2425    /// Function to handle subscripting operations: `SUBSCRIPT = subscript_function`
2426    Subscript(ObjectName),
2427    /// Internal storage size in bytes, or VARIABLE for variable-length: `INTERNALLENGTH = { internallength | VARIABLE }`
2428    InternalLength(UserDefinedTypeInternalLength),
2429    /// Indicates values are passed by value rather than by reference: `PASSEDBYVALUE`
2430    PassedByValue,
2431    /// Storage alignment requirement (1, 2, 4, or 8 bytes): `ALIGNMENT = alignment`
2432    Alignment(Alignment),
2433    /// Storage strategy for varlena types: `STORAGE = storage`
2434    Storage(UserDefinedTypeStorage),
2435    /// Copy properties from an existing type: `LIKE = like_type`
2436    Like(ObjectName),
2437    /// Type category for implicit casting rules (single char): `CATEGORY = category`
2438    Category(char),
2439    /// Whether this type is preferred within its category: `PREFERRED = preferred`
2440    Preferred(bool),
2441    /// Default value for the type: `DEFAULT = default`
2442    Default(Expr),
2443    /// Element type for array types: `ELEMENT = element`
2444    Element(DataType),
2445    /// Delimiter character for array value display: `DELIMITER = delimiter`
2446    Delimiter(String),
2447    /// Whether the type supports collation: `COLLATABLE = collatable`
2448    Collatable(bool),
2449}
2450
2451impl fmt::Display for UserDefinedTypeSqlDefinitionOption {
2452    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2453        match self {
2454            UserDefinedTypeSqlDefinitionOption::Input(name) => write!(f, "INPUT = {}", name),
2455            UserDefinedTypeSqlDefinitionOption::Output(name) => write!(f, "OUTPUT = {}", name),
2456            UserDefinedTypeSqlDefinitionOption::Receive(name) => write!(f, "RECEIVE = {}", name),
2457            UserDefinedTypeSqlDefinitionOption::Send(name) => write!(f, "SEND = {}", name),
2458            UserDefinedTypeSqlDefinitionOption::TypmodIn(name) => write!(f, "TYPMOD_IN = {}", name),
2459            UserDefinedTypeSqlDefinitionOption::TypmodOut(name) => {
2460                write!(f, "TYPMOD_OUT = {}", name)
2461            }
2462            UserDefinedTypeSqlDefinitionOption::Analyze(name) => write!(f, "ANALYZE = {}", name),
2463            UserDefinedTypeSqlDefinitionOption::Subscript(name) => {
2464                write!(f, "SUBSCRIPT = {}", name)
2465            }
2466            UserDefinedTypeSqlDefinitionOption::InternalLength(len) => {
2467                write!(f, "INTERNALLENGTH = {}", len)
2468            }
2469            UserDefinedTypeSqlDefinitionOption::PassedByValue => write!(f, "PASSEDBYVALUE"),
2470            UserDefinedTypeSqlDefinitionOption::Alignment(align) => {
2471                write!(f, "ALIGNMENT = {}", align)
2472            }
2473            UserDefinedTypeSqlDefinitionOption::Storage(storage) => {
2474                write!(f, "STORAGE = {}", storage)
2475            }
2476            UserDefinedTypeSqlDefinitionOption::Like(name) => write!(f, "LIKE = {}", name),
2477            UserDefinedTypeSqlDefinitionOption::Category(c) => write!(f, "CATEGORY = '{}'", c),
2478            UserDefinedTypeSqlDefinitionOption::Preferred(b) => write!(f, "PREFERRED = {}", b),
2479            UserDefinedTypeSqlDefinitionOption::Default(expr) => write!(f, "DEFAULT = {}", expr),
2480            UserDefinedTypeSqlDefinitionOption::Element(dt) => write!(f, "ELEMENT = {}", dt),
2481            UserDefinedTypeSqlDefinitionOption::Delimiter(s) => {
2482                write!(f, "DELIMITER = '{}'", escape_single_quote_string(s))
2483            }
2484            UserDefinedTypeSqlDefinitionOption::Collatable(b) => write!(f, "COLLATABLE = {}", b),
2485        }
2486    }
2487}
2488
2489/// PARTITION statement used in ALTER TABLE et al. such as in Hive and ClickHouse SQL.
2490/// For example, ClickHouse's OPTIMIZE TABLE supports syntax like PARTITION ID 'partition_id' and PARTITION expr.
2491/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2492#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2493#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2494#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2495pub enum Partition {
2496    Identifier(Ident),
2497    Expr(Expr),
2498    /// ClickHouse supports PART expr which represents physical partition in disk.
2499    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
2500    Part(Expr),
2501    Partitions(Vec<Expr>),
2502}
2503
2504impl fmt::Display for Partition {
2505    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2506        match self {
2507            Partition::Identifier(id) => write!(f, "PARTITION ID {id}"),
2508            Partition::Expr(expr) => write!(f, "PARTITION {expr}"),
2509            Partition::Part(expr) => write!(f, "PART {expr}"),
2510            Partition::Partitions(partitions) => {
2511                write!(f, "PARTITION ({})", display_comma_separated(partitions))
2512            }
2513        }
2514    }
2515}
2516
2517/// DEDUPLICATE statement used in OPTIMIZE TABLE et al. such as in ClickHouse SQL
2518/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2519#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2520#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2521#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2522pub enum Deduplicate {
2523    All,
2524    ByExpression(Expr),
2525}
2526
2527impl fmt::Display for Deduplicate {
2528    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2529        match self {
2530            Deduplicate::All => write!(f, "DEDUPLICATE"),
2531            Deduplicate::ByExpression(expr) => write!(f, "DEDUPLICATE BY {expr}"),
2532        }
2533    }
2534}
2535
2536/// Hive supports `CLUSTERED BY` statement in `CREATE TABLE`.
2537/// Syntax: `CLUSTERED BY (col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS`
2538///
2539/// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2540#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2541#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2542#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2543pub struct ClusteredBy {
2544    pub columns: Vec<Ident>,
2545    pub sorted_by: Option<Vec<OrderByExpr>>,
2546    pub num_buckets: Value,
2547}
2548
2549impl fmt::Display for ClusteredBy {
2550    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2551        write!(
2552            f,
2553            "CLUSTERED BY ({})",
2554            display_comma_separated(&self.columns)
2555        )?;
2556        if let Some(ref sorted_by) = self.sorted_by {
2557            write!(f, " SORTED BY ({})", display_comma_separated(sorted_by))?;
2558        }
2559        write!(f, " INTO {} BUCKETS", self.num_buckets)
2560    }
2561}
2562
2563/// CREATE INDEX statement.
2564#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2565#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2566#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2567pub struct CreateIndex {
2568    /// index name
2569    pub name: Option<ObjectName>,
2570    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2571    pub table_name: ObjectName,
2572    /// Index type used in the statement. Can also be found inside [`CreateIndex::index_options`]
2573    /// depending on the position of the option within the statement.
2574    pub using: Option<IndexType>,
2575    pub columns: Vec<IndexColumn>,
2576    pub unique: bool,
2577    pub concurrently: bool,
2578    pub if_not_exists: bool,
2579    pub include: Vec<Ident>,
2580    pub nulls_distinct: Option<bool>,
2581    /// WITH clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2582    pub with: Vec<Expr>,
2583    pub predicate: Option<Expr>,
2584    pub index_options: Vec<IndexOption>,
2585    /// [MySQL] allows a subset of options normally used for `ALTER TABLE`:
2586    ///
2587    /// - `ALGORITHM`
2588    /// - `LOCK`
2589    ///
2590    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/create-index.html
2591    pub alter_options: Vec<AlterTableOperation>,
2592}
2593
2594impl fmt::Display for CreateIndex {
2595    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2596        write!(
2597            f,
2598            "CREATE {unique}INDEX {concurrently}{if_not_exists}",
2599            unique = if self.unique { "UNIQUE " } else { "" },
2600            concurrently = if self.concurrently {
2601                "CONCURRENTLY "
2602            } else {
2603                ""
2604            },
2605            if_not_exists = if self.if_not_exists {
2606                "IF NOT EXISTS "
2607            } else {
2608                ""
2609            },
2610        )?;
2611        if let Some(value) = &self.name {
2612            write!(f, "{value} ")?;
2613        }
2614        write!(f, "ON {}", self.table_name)?;
2615        if let Some(value) = &self.using {
2616            write!(f, " USING {value} ")?;
2617        }
2618        write!(f, "({})", display_comma_separated(&self.columns))?;
2619        if !self.include.is_empty() {
2620            write!(f, " INCLUDE ({})", display_comma_separated(&self.include))?;
2621        }
2622        if let Some(value) = self.nulls_distinct {
2623            if value {
2624                write!(f, " NULLS DISTINCT")?;
2625            } else {
2626                write!(f, " NULLS NOT DISTINCT")?;
2627            }
2628        }
2629        if !self.with.is_empty() {
2630            write!(f, " WITH ({})", display_comma_separated(&self.with))?;
2631        }
2632        if let Some(predicate) = &self.predicate {
2633            write!(f, " WHERE {predicate}")?;
2634        }
2635        if !self.index_options.is_empty() {
2636            write!(f, " {}", display_separated(&self.index_options, " "))?;
2637        }
2638        if !self.alter_options.is_empty() {
2639            write!(f, " {}", display_separated(&self.alter_options, " "))?;
2640        }
2641        Ok(())
2642    }
2643}
2644
2645/// CREATE TABLE statement.
2646#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2647#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2648#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2649pub struct CreateTable {
2650    pub or_replace: bool,
2651    pub temporary: bool,
2652    pub external: bool,
2653    pub dynamic: bool,
2654    pub global: Option<bool>,
2655    pub if_not_exists: bool,
2656    pub transient: bool,
2657    pub volatile: bool,
2658    pub iceberg: bool,
2659    /// Table name
2660    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2661    pub name: ObjectName,
2662    /// Optional schema
2663    pub columns: Vec<ColumnDef>,
2664    pub constraints: Vec<TableConstraint>,
2665    pub hive_distribution: HiveDistributionStyle,
2666    pub hive_formats: Option<HiveFormat>,
2667    pub table_options: CreateTableOptions,
2668    pub file_format: Option<FileFormat>,
2669    pub location: Option<String>,
2670    pub query: Option<Box<Query>>,
2671    pub without_rowid: bool,
2672    pub like: Option<CreateTableLikeKind>,
2673    pub clone: Option<ObjectName>,
2674    pub version: Option<TableVersion>,
2675    // For Hive dialect, the table comment is after the column definitions without `=`,
2676    // so the `comment` field is optional and different than the comment field in the general options list.
2677    // [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2678    pub comment: Option<CommentDef>,
2679    pub on_commit: Option<OnCommit>,
2680    /// ClickHouse "ON CLUSTER" clause:
2681    /// <https://clickhouse.com/docs/en/sql-reference/distributed-ddl/>
2682    pub on_cluster: Option<Ident>,
2683    /// ClickHouse "PRIMARY KEY " clause.
2684    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
2685    pub primary_key: Option<Box<Expr>>,
2686    /// ClickHouse "ORDER BY " clause. Note that omitted ORDER BY is different
2687    /// than empty (represented as ()), the latter meaning "no sorting".
2688    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
2689    pub order_by: Option<OneOrManyWithParens<Expr>>,
2690    /// BigQuery: A partition expression for the table.
2691    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#partition_expression>
2692    pub partition_by: Option<Box<Expr>>,
2693    /// BigQuery: Table clustering column list.
2694    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#table_option_list>
2695    /// Snowflake: Table clustering list which contains base column, expressions on base columns.
2696    /// <https://docs.snowflake.com/en/user-guide/tables-clustering-keys#defining-a-clustering-key-for-a-table>
2697    pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
2698    /// Hive: Table clustering column list.
2699    /// <https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable>
2700    pub clustered_by: Option<ClusteredBy>,
2701    /// Postgres `INHERITs` clause, which contains the list of tables from which
2702    /// the new table inherits.
2703    /// <https://www.postgresql.org/docs/current/ddl-inherit.html>
2704    /// <https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-INHERITS>
2705    pub inherits: Option<Vec<ObjectName>>,
2706    /// PostgreSQL `PARTITION OF` clause to create a partition of a parent table.
2707    /// Contains the parent table name.
2708    /// <https://www.postgresql.org/docs/current/sql-createtable.html>
2709    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2710    pub partition_of: Option<ObjectName>,
2711    /// PostgreSQL partition bound specification for PARTITION OF.
2712    /// <https://www.postgresql.org/docs/current/sql-createtable.html>
2713    pub for_values: Option<ForValues>,
2714    /// SQLite "STRICT" clause.
2715    /// if the "STRICT" table-option keyword is added to the end, after the closing ")",
2716    /// then strict typing rules apply to that table.
2717    pub strict: bool,
2718    /// Snowflake "COPY GRANTS" clause
2719    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2720    pub copy_grants: bool,
2721    /// Snowflake "ENABLE_SCHEMA_EVOLUTION" clause
2722    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2723    pub enable_schema_evolution: Option<bool>,
2724    /// Snowflake "CHANGE_TRACKING" clause
2725    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2726    pub change_tracking: Option<bool>,
2727    /// Snowflake "DATA_RETENTION_TIME_IN_DAYS" clause
2728    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2729    pub data_retention_time_in_days: Option<u64>,
2730    /// Snowflake "MAX_DATA_EXTENSION_TIME_IN_DAYS" clause
2731    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2732    pub max_data_extension_time_in_days: Option<u64>,
2733    /// Snowflake "DEFAULT_DDL_COLLATION" clause
2734    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2735    pub default_ddl_collation: Option<String>,
2736    /// Snowflake "WITH AGGREGATION POLICY" clause
2737    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2738    pub with_aggregation_policy: Option<ObjectName>,
2739    /// Snowflake "WITH ROW ACCESS POLICY" clause
2740    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2741    pub with_row_access_policy: Option<RowAccessPolicy>,
2742    /// Snowflake "WITH TAG" clause
2743    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2744    pub with_tags: Option<Vec<Tag>>,
2745    /// Snowflake "EXTERNAL_VOLUME" clause for Iceberg tables
2746    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2747    pub external_volume: Option<String>,
2748    /// Snowflake "BASE_LOCATION" clause for Iceberg tables
2749    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2750    pub base_location: Option<String>,
2751    /// Snowflake "CATALOG" clause for Iceberg tables
2752    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2753    pub catalog: Option<String>,
2754    /// Snowflake "CATALOG_SYNC" clause for Iceberg tables
2755    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2756    pub catalog_sync: Option<String>,
2757    /// Snowflake "STORAGE_SERIALIZATION_POLICY" clause for Iceberg tables
2758    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2759    pub storage_serialization_policy: Option<StorageSerializationPolicy>,
2760    /// Snowflake "TARGET_LAG" clause for dybamic tables
2761    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2762    pub target_lag: Option<String>,
2763    /// Snowflake "WAREHOUSE" clause for dybamic tables
2764    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2765    pub warehouse: Option<Ident>,
2766    /// Snowflake "REFRESH_MODE" clause for dybamic tables
2767    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2768    pub refresh_mode: Option<RefreshModeKind>,
2769    /// Snowflake "INITIALIZE" clause for dybamic tables
2770    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2771    pub initialize: Option<InitializeKind>,
2772    /// Snowflake "REQUIRE USER" clause for dybamic tables
2773    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2774    pub require_user: bool,
2775}
2776
2777impl fmt::Display for CreateTable {
2778    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2779        // We want to allow the following options
2780        // Empty column list, allowed by PostgreSQL:
2781        //   `CREATE TABLE t ()`
2782        // No columns provided for CREATE TABLE AS:
2783        //   `CREATE TABLE t AS SELECT a from t2`
2784        // Columns provided for CREATE TABLE AS:
2785        //   `CREATE TABLE t (a INT) AS SELECT a from t2`
2786        write!(
2787            f,
2788            "CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}{dynamic}{iceberg}TABLE {if_not_exists}{name}",
2789            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
2790            external = if self.external { "EXTERNAL " } else { "" },
2791            global = self.global
2792                .map(|global| {
2793                    if global {
2794                        "GLOBAL "
2795                    } else {
2796                        "LOCAL "
2797                    }
2798                })
2799                .unwrap_or(""),
2800            if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
2801            temporary = if self.temporary { "TEMPORARY " } else { "" },
2802            transient = if self.transient { "TRANSIENT " } else { "" },
2803            volatile = if self.volatile { "VOLATILE " } else { "" },
2804            // Only for Snowflake
2805            iceberg = if self.iceberg { "ICEBERG " } else { "" },
2806            dynamic = if self.dynamic { "DYNAMIC " } else { "" },
2807            name = self.name,
2808        )?;
2809        if let Some(partition_of) = &self.partition_of {
2810            write!(f, " PARTITION OF {partition_of}")?;
2811        }
2812        if let Some(on_cluster) = &self.on_cluster {
2813            write!(f, " ON CLUSTER {on_cluster}")?;
2814        }
2815        if !self.columns.is_empty() || !self.constraints.is_empty() {
2816            f.write_str(" (")?;
2817            NewLine.fmt(f)?;
2818            Indent(DisplayCommaSeparated(&self.columns)).fmt(f)?;
2819            if !self.columns.is_empty() && !self.constraints.is_empty() {
2820                f.write_str(",")?;
2821                SpaceOrNewline.fmt(f)?;
2822            }
2823            Indent(DisplayCommaSeparated(&self.constraints)).fmt(f)?;
2824            NewLine.fmt(f)?;
2825            f.write_str(")")?;
2826        } else if self.query.is_none()
2827            && self.like.is_none()
2828            && self.clone.is_none()
2829            && self.partition_of.is_none()
2830        {
2831            // PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
2832            f.write_str(" ()")?;
2833        } else if let Some(CreateTableLikeKind::Parenthesized(like_in_columns_list)) = &self.like {
2834            write!(f, " ({like_in_columns_list})")?;
2835        }
2836        if let Some(for_values) = &self.for_values {
2837            write!(f, " {for_values}")?;
2838        }
2839
2840        // Hive table comment should be after column definitions, please refer to:
2841        // [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2842        if let Some(comment) = &self.comment {
2843            write!(f, " COMMENT '{comment}'")?;
2844        }
2845
2846        // Only for SQLite
2847        if self.without_rowid {
2848            write!(f, " WITHOUT ROWID")?;
2849        }
2850
2851        if let Some(CreateTableLikeKind::Plain(like)) = &self.like {
2852            write!(f, " {like}")?;
2853        }
2854
2855        if let Some(c) = &self.clone {
2856            write!(f, " CLONE {c}")?;
2857        }
2858
2859        if let Some(version) = &self.version {
2860            write!(f, " {version}")?;
2861        }
2862
2863        match &self.hive_distribution {
2864            HiveDistributionStyle::PARTITIONED { columns } => {
2865                write!(f, " PARTITIONED BY ({})", display_comma_separated(columns))?;
2866            }
2867            HiveDistributionStyle::SKEWED {
2868                columns,
2869                on,
2870                stored_as_directories,
2871            } => {
2872                write!(
2873                    f,
2874                    " SKEWED BY ({})) ON ({})",
2875                    display_comma_separated(columns),
2876                    display_comma_separated(on)
2877                )?;
2878                if *stored_as_directories {
2879                    write!(f, " STORED AS DIRECTORIES")?;
2880                }
2881            }
2882            _ => (),
2883        }
2884
2885        if let Some(clustered_by) = &self.clustered_by {
2886            write!(f, " {clustered_by}")?;
2887        }
2888
2889        if let Some(HiveFormat {
2890            row_format,
2891            serde_properties,
2892            storage,
2893            location,
2894        }) = &self.hive_formats
2895        {
2896            match row_format {
2897                Some(HiveRowFormat::SERDE { class }) => write!(f, " ROW FORMAT SERDE '{class}'")?,
2898                Some(HiveRowFormat::DELIMITED { delimiters }) => {
2899                    write!(f, " ROW FORMAT DELIMITED")?;
2900                    if !delimiters.is_empty() {
2901                        write!(f, " {}", display_separated(delimiters, " "))?;
2902                    }
2903                }
2904                None => (),
2905            }
2906            match storage {
2907                Some(HiveIOFormat::IOF {
2908                    input_format,
2909                    output_format,
2910                }) => write!(
2911                    f,
2912                    " STORED AS INPUTFORMAT {input_format} OUTPUTFORMAT {output_format}"
2913                )?,
2914                Some(HiveIOFormat::FileFormat { format }) if !self.external => {
2915                    write!(f, " STORED AS {format}")?
2916                }
2917                _ => (),
2918            }
2919            if let Some(serde_properties) = serde_properties.as_ref() {
2920                write!(
2921                    f,
2922                    " WITH SERDEPROPERTIES ({})",
2923                    display_comma_separated(serde_properties)
2924                )?;
2925            }
2926            if !self.external {
2927                if let Some(loc) = location {
2928                    write!(f, " LOCATION '{loc}'")?;
2929                }
2930            }
2931        }
2932        if self.external {
2933            if let Some(file_format) = self.file_format {
2934                write!(f, " STORED AS {file_format}")?;
2935            }
2936            if let Some(location) = &self.location {
2937                write!(f, " LOCATION '{location}'")?;
2938            }
2939        }
2940
2941        match &self.table_options {
2942            options @ CreateTableOptions::With(_)
2943            | options @ CreateTableOptions::Plain(_)
2944            | options @ CreateTableOptions::TableProperties(_) => write!(f, " {options}")?,
2945            _ => (),
2946        }
2947
2948        if let Some(primary_key) = &self.primary_key {
2949            write!(f, " PRIMARY KEY {primary_key}")?;
2950        }
2951        if let Some(order_by) = &self.order_by {
2952            write!(f, " ORDER BY {order_by}")?;
2953        }
2954        if let Some(inherits) = &self.inherits {
2955            write!(f, " INHERITS ({})", display_comma_separated(inherits))?;
2956        }
2957        if let Some(partition_by) = self.partition_by.as_ref() {
2958            write!(f, " PARTITION BY {partition_by}")?;
2959        }
2960        if let Some(cluster_by) = self.cluster_by.as_ref() {
2961            write!(f, " CLUSTER BY {cluster_by}")?;
2962        }
2963        if let options @ CreateTableOptions::Options(_) = &self.table_options {
2964            write!(f, " {options}")?;
2965        }
2966        if let Some(external_volume) = self.external_volume.as_ref() {
2967            write!(f, " EXTERNAL_VOLUME='{external_volume}'")?;
2968        }
2969
2970        if let Some(catalog) = self.catalog.as_ref() {
2971            write!(f, " CATALOG='{catalog}'")?;
2972        }
2973
2974        if self.iceberg {
2975            if let Some(base_location) = self.base_location.as_ref() {
2976                write!(f, " BASE_LOCATION='{base_location}'")?;
2977            }
2978        }
2979
2980        if let Some(catalog_sync) = self.catalog_sync.as_ref() {
2981            write!(f, " CATALOG_SYNC='{catalog_sync}'")?;
2982        }
2983
2984        if let Some(storage_serialization_policy) = self.storage_serialization_policy.as_ref() {
2985            write!(
2986                f,
2987                " STORAGE_SERIALIZATION_POLICY={storage_serialization_policy}"
2988            )?;
2989        }
2990
2991        if self.copy_grants {
2992            write!(f, " COPY GRANTS")?;
2993        }
2994
2995        if let Some(is_enabled) = self.enable_schema_evolution {
2996            write!(
2997                f,
2998                " ENABLE_SCHEMA_EVOLUTION={}",
2999                if is_enabled { "TRUE" } else { "FALSE" }
3000            )?;
3001        }
3002
3003        if let Some(is_enabled) = self.change_tracking {
3004            write!(
3005                f,
3006                " CHANGE_TRACKING={}",
3007                if is_enabled { "TRUE" } else { "FALSE" }
3008            )?;
3009        }
3010
3011        if let Some(data_retention_time_in_days) = self.data_retention_time_in_days {
3012            write!(
3013                f,
3014                " DATA_RETENTION_TIME_IN_DAYS={data_retention_time_in_days}",
3015            )?;
3016        }
3017
3018        if let Some(max_data_extension_time_in_days) = self.max_data_extension_time_in_days {
3019            write!(
3020                f,
3021                " MAX_DATA_EXTENSION_TIME_IN_DAYS={max_data_extension_time_in_days}",
3022            )?;
3023        }
3024
3025        if let Some(default_ddl_collation) = &self.default_ddl_collation {
3026            write!(f, " DEFAULT_DDL_COLLATION='{default_ddl_collation}'",)?;
3027        }
3028
3029        if let Some(with_aggregation_policy) = &self.with_aggregation_policy {
3030            write!(f, " WITH AGGREGATION POLICY {with_aggregation_policy}",)?;
3031        }
3032
3033        if let Some(row_access_policy) = &self.with_row_access_policy {
3034            write!(f, " {row_access_policy}",)?;
3035        }
3036
3037        if let Some(tag) = &self.with_tags {
3038            write!(f, " WITH TAG ({})", display_comma_separated(tag.as_slice()))?;
3039        }
3040
3041        if let Some(target_lag) = &self.target_lag {
3042            write!(f, " TARGET_LAG='{target_lag}'")?;
3043        }
3044
3045        if let Some(warehouse) = &self.warehouse {
3046            write!(f, " WAREHOUSE={warehouse}")?;
3047        }
3048
3049        if let Some(refresh_mode) = &self.refresh_mode {
3050            write!(f, " REFRESH_MODE={refresh_mode}")?;
3051        }
3052
3053        if let Some(initialize) = &self.initialize {
3054            write!(f, " INITIALIZE={initialize}")?;
3055        }
3056
3057        if self.require_user {
3058            write!(f, " REQUIRE USER")?;
3059        }
3060
3061        if self.on_commit.is_some() {
3062            let on_commit = match self.on_commit {
3063                Some(OnCommit::DeleteRows) => "ON COMMIT DELETE ROWS",
3064                Some(OnCommit::PreserveRows) => "ON COMMIT PRESERVE ROWS",
3065                Some(OnCommit::Drop) => "ON COMMIT DROP",
3066                None => "",
3067            };
3068            write!(f, " {on_commit}")?;
3069        }
3070        if self.strict {
3071            write!(f, " STRICT")?;
3072        }
3073        if let Some(query) = &self.query {
3074            write!(f, " AS {query}")?;
3075        }
3076        Ok(())
3077    }
3078}
3079
3080/// PostgreSQL partition bound specification for PARTITION OF.
3081///
3082/// Specifies partition bounds for a child partition table.
3083///
3084/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createtable.html)
3085#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3086#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3087#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3088pub enum ForValues {
3089    /// `FOR VALUES IN (expr, ...)`
3090    In(Vec<Expr>),
3091    /// `FOR VALUES FROM (expr|MINVALUE|MAXVALUE, ...) TO (expr|MINVALUE|MAXVALUE, ...)`
3092    From {
3093        from: Vec<PartitionBoundValue>,
3094        to: Vec<PartitionBoundValue>,
3095    },
3096    /// `FOR VALUES WITH (MODULUS n, REMAINDER r)`
3097    With { modulus: u64, remainder: u64 },
3098    /// `DEFAULT`
3099    Default,
3100}
3101
3102impl fmt::Display for ForValues {
3103    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3104        match self {
3105            ForValues::In(values) => {
3106                write!(f, "FOR VALUES IN ({})", display_comma_separated(values))
3107            }
3108            ForValues::From { from, to } => {
3109                write!(
3110                    f,
3111                    "FOR VALUES FROM ({}) TO ({})",
3112                    display_comma_separated(from),
3113                    display_comma_separated(to)
3114                )
3115            }
3116            ForValues::With { modulus, remainder } => {
3117                write!(
3118                    f,
3119                    "FOR VALUES WITH (MODULUS {modulus}, REMAINDER {remainder})"
3120                )
3121            }
3122            ForValues::Default => write!(f, "DEFAULT"),
3123        }
3124    }
3125}
3126
3127/// A value in a partition bound specification.
3128///
3129/// Used in RANGE partition bounds where values can be expressions,
3130/// MINVALUE (negative infinity), or MAXVALUE (positive infinity).
3131#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3132#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3133#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3134pub enum PartitionBoundValue {
3135    Expr(Expr),
3136    MinValue,
3137    MaxValue,
3138}
3139
3140impl fmt::Display for PartitionBoundValue {
3141    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3142        match self {
3143            PartitionBoundValue::Expr(expr) => write!(f, "{expr}"),
3144            PartitionBoundValue::MinValue => write!(f, "MINVALUE"),
3145            PartitionBoundValue::MaxValue => write!(f, "MAXVALUE"),
3146        }
3147    }
3148}
3149
3150#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3151#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3152#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3153/// ```sql
3154/// CREATE DOMAIN name [ AS ] data_type
3155///         [ COLLATE collation ]
3156///         [ DEFAULT expression ]
3157///         [ domain_constraint [ ... ] ]
3158///
3159///     where domain_constraint is:
3160///
3161///     [ CONSTRAINT constraint_name ]
3162///     { NOT NULL | NULL | CHECK (expression) }
3163/// ```
3164/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createdomain.html)
3165pub struct CreateDomain {
3166    /// The name of the domain to be created.
3167    pub name: ObjectName,
3168    /// The data type of the domain.
3169    pub data_type: DataType,
3170    /// The collation of the domain.
3171    pub collation: Option<Ident>,
3172    /// The default value of the domain.
3173    pub default: Option<Expr>,
3174    /// The constraints of the domain.
3175    pub constraints: Vec<TableConstraint>,
3176}
3177
3178impl fmt::Display for CreateDomain {
3179    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3180        write!(
3181            f,
3182            "CREATE DOMAIN {name} AS {data_type}",
3183            name = self.name,
3184            data_type = self.data_type
3185        )?;
3186        if let Some(collation) = &self.collation {
3187            write!(f, " COLLATE {collation}")?;
3188        }
3189        if let Some(default) = &self.default {
3190            write!(f, " DEFAULT {default}")?;
3191        }
3192        if !self.constraints.is_empty() {
3193            write!(f, " {}", display_separated(&self.constraints, " "))?;
3194        }
3195        Ok(())
3196    }
3197}
3198
3199#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3200#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3201#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3202pub struct CreateFunction {
3203    /// True if this is a `CREATE OR ALTER FUNCTION` statement
3204    ///
3205    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql?view=sql-server-ver16#or-alter)
3206    pub or_alter: bool,
3207    pub or_replace: bool,
3208    pub temporary: bool,
3209    pub if_not_exists: bool,
3210    pub name: ObjectName,
3211    pub args: Option<Vec<OperateFunctionArg>>,
3212    pub return_type: Option<DataType>,
3213    /// The expression that defines the function.
3214    ///
3215    /// Examples:
3216    /// ```sql
3217    /// AS ((SELECT 1))
3218    /// AS "console.log();"
3219    /// ```
3220    pub function_body: Option<CreateFunctionBody>,
3221    /// Behavior attribute for the function
3222    ///
3223    /// IMMUTABLE | STABLE | VOLATILE
3224    ///
3225    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3226    pub behavior: Option<FunctionBehavior>,
3227    /// CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
3228    ///
3229    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3230    pub called_on_null: Option<FunctionCalledOnNull>,
3231    /// PARALLEL { UNSAFE | RESTRICTED | SAFE }
3232    ///
3233    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3234    pub parallel: Option<FunctionParallel>,
3235    /// SECURITY { DEFINER | INVOKER }
3236    ///
3237    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3238    pub security: Option<FunctionSecurity>,
3239    /// SET configuration_parameter clauses
3240    ///
3241    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3242    pub set_params: Vec<FunctionDefinitionSetParam>,
3243    /// USING ... (Hive only)
3244    pub using: Option<CreateFunctionUsing>,
3245    /// Language used in a UDF definition.
3246    ///
3247    /// Example:
3248    /// ```sql
3249    /// CREATE FUNCTION foo() LANGUAGE js AS "console.log();"
3250    /// ```
3251    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_javascript_udf)
3252    pub language: Option<Ident>,
3253    /// Determinism keyword used for non-sql UDF definitions.
3254    ///
3255    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
3256    pub determinism_specifier: Option<FunctionDeterminismSpecifier>,
3257    /// List of options for creating the function.
3258    ///
3259    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
3260    pub options: Option<Vec<SqlOption>>,
3261    /// Connection resource for a remote function.
3262    ///
3263    /// Example:
3264    /// ```sql
3265    /// CREATE FUNCTION foo()
3266    /// RETURNS FLOAT64
3267    /// REMOTE WITH CONNECTION us.myconnection
3268    /// ```
3269    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
3270    pub remote_connection: Option<ObjectName>,
3271}
3272
3273impl fmt::Display for CreateFunction {
3274    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3275        write!(
3276            f,
3277            "CREATE {or_alter}{or_replace}{temp}FUNCTION {if_not_exists}{name}",
3278            name = self.name,
3279            temp = if self.temporary { "TEMPORARY " } else { "" },
3280            or_alter = if self.or_alter { "OR ALTER " } else { "" },
3281            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
3282            if_not_exists = if self.if_not_exists {
3283                "IF NOT EXISTS "
3284            } else {
3285                ""
3286            },
3287        )?;
3288        if let Some(args) = &self.args {
3289            write!(f, "({})", display_comma_separated(args))?;
3290        }
3291        if let Some(return_type) = &self.return_type {
3292            write!(f, " RETURNS {return_type}")?;
3293        }
3294        if let Some(determinism_specifier) = &self.determinism_specifier {
3295            write!(f, " {determinism_specifier}")?;
3296        }
3297        if let Some(language) = &self.language {
3298            write!(f, " LANGUAGE {language}")?;
3299        }
3300        if let Some(behavior) = &self.behavior {
3301            write!(f, " {behavior}")?;
3302        }
3303        if let Some(called_on_null) = &self.called_on_null {
3304            write!(f, " {called_on_null}")?;
3305        }
3306        if let Some(parallel) = &self.parallel {
3307            write!(f, " {parallel}")?;
3308        }
3309        if let Some(security) = &self.security {
3310            write!(f, " {security}")?;
3311        }
3312        for set_param in &self.set_params {
3313            write!(f, " {set_param}")?;
3314        }
3315        if let Some(remote_connection) = &self.remote_connection {
3316            write!(f, " REMOTE WITH CONNECTION {remote_connection}")?;
3317        }
3318        if let Some(CreateFunctionBody::AsBeforeOptions { body, link_symbol }) = &self.function_body
3319        {
3320            write!(f, " AS {body}")?;
3321            if let Some(link_symbol) = link_symbol {
3322                write!(f, ", {link_symbol}")?;
3323            }
3324        }
3325        if let Some(CreateFunctionBody::Return(function_body)) = &self.function_body {
3326            write!(f, " RETURN {function_body}")?;
3327        }
3328        if let Some(CreateFunctionBody::AsReturnExpr(function_body)) = &self.function_body {
3329            write!(f, " AS RETURN {function_body}")?;
3330        }
3331        if let Some(CreateFunctionBody::AsReturnSelect(function_body)) = &self.function_body {
3332            write!(f, " AS RETURN {function_body}")?;
3333        }
3334        if let Some(using) = &self.using {
3335            write!(f, " {using}")?;
3336        }
3337        if let Some(options) = &self.options {
3338            write!(
3339                f,
3340                " OPTIONS({})",
3341                display_comma_separated(options.as_slice())
3342            )?;
3343        }
3344        if let Some(CreateFunctionBody::AsAfterOptions(function_body)) = &self.function_body {
3345            write!(f, " AS {function_body}")?;
3346        }
3347        if let Some(CreateFunctionBody::AsBeginEnd(bes)) = &self.function_body {
3348            write!(f, " AS {bes}")?;
3349        }
3350        Ok(())
3351    }
3352}
3353
3354/// ```sql
3355/// CREATE CONNECTOR [IF NOT EXISTS] connector_name
3356/// [TYPE datasource_type]
3357/// [URL datasource_url]
3358/// [COMMENT connector_comment]
3359/// [WITH DCPROPERTIES(property_name=property_value, ...)]
3360/// ```
3361///
3362/// [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
3363#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3364#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3365#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3366pub struct CreateConnector {
3367    pub name: Ident,
3368    pub if_not_exists: bool,
3369    pub connector_type: Option<String>,
3370    pub url: Option<String>,
3371    pub comment: Option<CommentDef>,
3372    pub with_dcproperties: Option<Vec<SqlOption>>,
3373}
3374
3375impl fmt::Display for CreateConnector {
3376    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3377        write!(
3378            f,
3379            "CREATE CONNECTOR {if_not_exists}{name}",
3380            if_not_exists = if self.if_not_exists {
3381                "IF NOT EXISTS "
3382            } else {
3383                ""
3384            },
3385            name = self.name,
3386        )?;
3387
3388        if let Some(connector_type) = &self.connector_type {
3389            write!(f, " TYPE '{connector_type}'")?;
3390        }
3391
3392        if let Some(url) = &self.url {
3393            write!(f, " URL '{url}'")?;
3394        }
3395
3396        if let Some(comment) = &self.comment {
3397            write!(f, " COMMENT = '{comment}'")?;
3398        }
3399
3400        if let Some(with_dcproperties) = &self.with_dcproperties {
3401            write!(
3402                f,
3403                " WITH DCPROPERTIES({})",
3404                display_comma_separated(with_dcproperties)
3405            )?;
3406        }
3407
3408        Ok(())
3409    }
3410}
3411
3412/// An `ALTER SCHEMA` (`Statement::AlterSchema`) operation.
3413///
3414/// See [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#alter_schema_collate_statement)
3415/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterschema.html)
3416#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3417#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3418#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3419pub enum AlterSchemaOperation {
3420    SetDefaultCollate {
3421        collate: Expr,
3422    },
3423    AddReplica {
3424        replica: Ident,
3425        options: Option<Vec<SqlOption>>,
3426    },
3427    DropReplica {
3428        replica: Ident,
3429    },
3430    SetOptionsParens {
3431        options: Vec<SqlOption>,
3432    },
3433    Rename {
3434        name: ObjectName,
3435    },
3436    OwnerTo {
3437        owner: Owner,
3438    },
3439}
3440
3441impl fmt::Display for AlterSchemaOperation {
3442    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3443        match self {
3444            AlterSchemaOperation::SetDefaultCollate { collate } => {
3445                write!(f, "SET DEFAULT COLLATE {collate}")
3446            }
3447            AlterSchemaOperation::AddReplica { replica, options } => {
3448                write!(f, "ADD REPLICA {replica}")?;
3449                if let Some(options) = options {
3450                    write!(f, " OPTIONS ({})", display_comma_separated(options))?;
3451                }
3452                Ok(())
3453            }
3454            AlterSchemaOperation::DropReplica { replica } => write!(f, "DROP REPLICA {replica}"),
3455            AlterSchemaOperation::SetOptionsParens { options } => {
3456                write!(f, "SET OPTIONS ({})", display_comma_separated(options))
3457            }
3458            AlterSchemaOperation::Rename { name } => write!(f, "RENAME TO {name}"),
3459            AlterSchemaOperation::OwnerTo { owner } => write!(f, "OWNER TO {owner}"),
3460        }
3461    }
3462}
3463/// `RenameTableNameKind` is the kind used in an `ALTER TABLE _ RENAME` statement.
3464///
3465/// Note: [MySQL] is the only database that supports the AS keyword for this operation.
3466///
3467/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
3468#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3469#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3470#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3471pub enum RenameTableNameKind {
3472    As(ObjectName),
3473    To(ObjectName),
3474}
3475
3476impl fmt::Display for RenameTableNameKind {
3477    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3478        match self {
3479            RenameTableNameKind::As(name) => write!(f, "AS {name}"),
3480            RenameTableNameKind::To(name) => write!(f, "TO {name}"),
3481        }
3482    }
3483}
3484
3485#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3486#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3487#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3488pub struct AlterSchema {
3489    pub name: ObjectName,
3490    pub if_exists: bool,
3491    pub operations: Vec<AlterSchemaOperation>,
3492}
3493
3494impl fmt::Display for AlterSchema {
3495    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3496        write!(f, "ALTER SCHEMA ")?;
3497        if self.if_exists {
3498            write!(f, "IF EXISTS ")?;
3499        }
3500        write!(f, "{}", self.name)?;
3501        for operation in &self.operations {
3502            write!(f, " {operation}")?;
3503        }
3504
3505        Ok(())
3506    }
3507}
3508
3509impl Spanned for RenameTableNameKind {
3510    fn span(&self) -> Span {
3511        match self {
3512            RenameTableNameKind::As(name) => name.span(),
3513            RenameTableNameKind::To(name) => name.span(),
3514        }
3515    }
3516}
3517
3518#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3519#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3520#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3521/// Whether the syntax used for the trigger object (ROW or STATEMENT) is `FOR` or `FOR EACH`.
3522pub enum TriggerObjectKind {
3523    /// The `FOR` syntax is used.
3524    For(TriggerObject),
3525    /// The `FOR EACH` syntax is used.
3526    ForEach(TriggerObject),
3527}
3528
3529impl Display for TriggerObjectKind {
3530    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3531        match self {
3532            TriggerObjectKind::For(obj) => write!(f, "FOR {obj}"),
3533            TriggerObjectKind::ForEach(obj) => write!(f, "FOR EACH {obj}"),
3534        }
3535    }
3536}
3537
3538#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3539#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3540#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3541/// CREATE TRIGGER
3542///
3543/// Examples:
3544///
3545/// ```sql
3546/// CREATE TRIGGER trigger_name
3547/// BEFORE INSERT ON table_name
3548/// FOR EACH ROW
3549/// EXECUTE FUNCTION trigger_function();
3550/// ```
3551///
3552/// Postgres: <https://www.postgresql.org/docs/current/sql-createtrigger.html>
3553/// SQL Server: <https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql>
3554pub struct CreateTrigger {
3555    /// True if this is a `CREATE OR ALTER TRIGGER` statement
3556    ///
3557    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql?view=sql-server-ver16#arguments)
3558    pub or_alter: bool,
3559    /// True if this is a temporary trigger.
3560    ///
3561    /// Examples:
3562    ///
3563    /// ```sql
3564    /// CREATE TEMP TRIGGER trigger_name
3565    /// ```
3566    ///
3567    /// or
3568    ///
3569    /// ```sql
3570    /// CREATE TEMPORARY TRIGGER trigger_name;
3571    /// CREATE TEMP TRIGGER trigger_name;
3572    /// ```
3573    ///
3574    /// [SQLite](https://sqlite.org/lang_createtrigger.html#temp_triggers_on_non_temp_tables)
3575    pub temporary: bool,
3576    /// The `OR REPLACE` clause is used to re-create the trigger if it already exists.
3577    ///
3578    /// Example:
3579    /// ```sql
3580    /// CREATE OR REPLACE TRIGGER trigger_name
3581    /// AFTER INSERT ON table_name
3582    /// FOR EACH ROW
3583    /// EXECUTE FUNCTION trigger_function();
3584    /// ```
3585    pub or_replace: bool,
3586    /// The `CONSTRAINT` keyword is used to create a trigger as a constraint.
3587    pub is_constraint: bool,
3588    /// The name of the trigger to be created.
3589    pub name: ObjectName,
3590    /// Determines whether the function is called before, after, or instead of the event.
3591    ///
3592    /// Example of BEFORE:
3593    ///
3594    /// ```sql
3595    /// CREATE TRIGGER trigger_name
3596    /// BEFORE INSERT ON table_name
3597    /// FOR EACH ROW
3598    /// EXECUTE FUNCTION trigger_function();
3599    /// ```
3600    ///
3601    /// Example of AFTER:
3602    ///
3603    /// ```sql
3604    /// CREATE TRIGGER trigger_name
3605    /// AFTER INSERT ON table_name
3606    /// FOR EACH ROW
3607    /// EXECUTE FUNCTION trigger_function();
3608    /// ```
3609    ///
3610    /// Example of INSTEAD OF:
3611    ///
3612    /// ```sql
3613    /// CREATE TRIGGER trigger_name
3614    /// INSTEAD OF INSERT ON table_name
3615    /// FOR EACH ROW
3616    /// EXECUTE FUNCTION trigger_function();
3617    /// ```
3618    pub period: Option<TriggerPeriod>,
3619    /// Whether the trigger period was specified before the target table name.
3620    /// This does not refer to whether the period is BEFORE, AFTER, or INSTEAD OF,
3621    /// but rather the position of the period clause in relation to the table name.
3622    ///
3623    /// ```sql
3624    /// -- period_before_table == true: Postgres, MySQL, and standard SQL
3625    /// CREATE TRIGGER t BEFORE INSERT ON table_name ...;
3626    /// -- period_before_table == false: MSSQL
3627    /// CREATE TRIGGER t ON table_name BEFORE INSERT ...;
3628    /// ```
3629    pub period_before_table: bool,
3630    /// Multiple events can be specified using OR, such as `INSERT`, `UPDATE`, `DELETE`, or `TRUNCATE`.
3631    pub events: Vec<TriggerEvent>,
3632    /// The table on which the trigger is to be created.
3633    pub table_name: ObjectName,
3634    /// The optional referenced table name that can be referenced via
3635    /// the `FROM` keyword.
3636    pub referenced_table_name: Option<ObjectName>,
3637    /// This keyword immediately precedes the declaration of one or two relation names that provide access to the transition relations of the triggering statement.
3638    pub referencing: Vec<TriggerReferencing>,
3639    /// This specifies whether the trigger function should be fired once for
3640    /// every row affected by the trigger event, or just once per SQL statement.
3641    /// This is optional in some SQL dialects, such as SQLite, and if not specified, in
3642    /// those cases, the implied default is `FOR EACH ROW`.
3643    pub trigger_object: Option<TriggerObjectKind>,
3644    ///  Triggering conditions
3645    pub condition: Option<Expr>,
3646    /// Execute logic block
3647    pub exec_body: Option<TriggerExecBody>,
3648    /// For MSSQL and dialects where statements are preceded by `AS`
3649    pub statements_as: bool,
3650    /// For SQL dialects with statement(s) for a body
3651    pub statements: Option<ConditionalStatements>,
3652    /// The characteristic of the trigger, which include whether the trigger is `DEFERRABLE`, `INITIALLY DEFERRED`, or `INITIALLY IMMEDIATE`,
3653    pub characteristics: Option<ConstraintCharacteristics>,
3654}
3655
3656impl Display for CreateTrigger {
3657    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3658        let CreateTrigger {
3659            or_alter,
3660            temporary,
3661            or_replace,
3662            is_constraint,
3663            name,
3664            period_before_table,
3665            period,
3666            events,
3667            table_name,
3668            referenced_table_name,
3669            referencing,
3670            trigger_object,
3671            condition,
3672            exec_body,
3673            statements_as,
3674            statements,
3675            characteristics,
3676        } = self;
3677        write!(
3678            f,
3679            "CREATE {temporary}{or_alter}{or_replace}{is_constraint}TRIGGER {name} ",
3680            temporary = if *temporary { "TEMPORARY " } else { "" },
3681            or_alter = if *or_alter { "OR ALTER " } else { "" },
3682            or_replace = if *or_replace { "OR REPLACE " } else { "" },
3683            is_constraint = if *is_constraint { "CONSTRAINT " } else { "" },
3684        )?;
3685
3686        if *period_before_table {
3687            if let Some(p) = period {
3688                write!(f, "{p} ")?;
3689            }
3690            if !events.is_empty() {
3691                write!(f, "{} ", display_separated(events, " OR "))?;
3692            }
3693            write!(f, "ON {table_name}")?;
3694        } else {
3695            write!(f, "ON {table_name} ")?;
3696            if let Some(p) = period {
3697                write!(f, "{p}")?;
3698            }
3699            if !events.is_empty() {
3700                write!(f, " {}", display_separated(events, ", "))?;
3701            }
3702        }
3703
3704        if let Some(referenced_table_name) = referenced_table_name {
3705            write!(f, " FROM {referenced_table_name}")?;
3706        }
3707
3708        if let Some(characteristics) = characteristics {
3709            write!(f, " {characteristics}")?;
3710        }
3711
3712        if !referencing.is_empty() {
3713            write!(f, " REFERENCING {}", display_separated(referencing, " "))?;
3714        }
3715
3716        if let Some(trigger_object) = trigger_object {
3717            write!(f, " {trigger_object}")?;
3718        }
3719        if let Some(condition) = condition {
3720            write!(f, " WHEN {condition}")?;
3721        }
3722        if let Some(exec_body) = exec_body {
3723            write!(f, " EXECUTE {exec_body}")?;
3724        }
3725        if let Some(statements) = statements {
3726            if *statements_as {
3727                write!(f, " AS")?;
3728            }
3729            write!(f, " {statements}")?;
3730        }
3731        Ok(())
3732    }
3733}
3734
3735#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3736#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3737#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3738/// DROP TRIGGER
3739///
3740/// ```sql
3741/// DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
3742/// ```
3743///
3744pub struct DropTrigger {
3745    /// Whether to include the `IF EXISTS` clause.
3746    pub if_exists: bool,
3747    /// The name of the trigger to be dropped.
3748    pub trigger_name: ObjectName,
3749    /// The name of the table from which the trigger is to be dropped.
3750    pub table_name: Option<ObjectName>,
3751    /// `CASCADE` or `RESTRICT`
3752    pub option: Option<ReferentialAction>,
3753}
3754
3755impl fmt::Display for DropTrigger {
3756    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3757        let DropTrigger {
3758            if_exists,
3759            trigger_name,
3760            table_name,
3761            option,
3762        } = self;
3763        write!(f, "DROP TRIGGER")?;
3764        if *if_exists {
3765            write!(f, " IF EXISTS")?;
3766        }
3767        match &table_name {
3768            Some(table_name) => write!(f, " {trigger_name} ON {table_name}")?,
3769            None => write!(f, " {trigger_name}")?,
3770        };
3771        if let Some(option) = option {
3772            write!(f, " {option}")?;
3773        }
3774        Ok(())
3775    }
3776}
3777
3778/// A `TRUNCATE` statement.
3779///
3780/// ```sql
3781/// TRUNCATE TABLE table_names [PARTITION (partitions)] [RESTART IDENTITY | CONTINUE IDENTITY] [CASCADE | RESTRICT] [ON CLUSTER cluster_name]
3782/// ```
3783#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3784#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3785#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3786pub struct Truncate {
3787    /// Table names to truncate
3788    pub table_names: Vec<super::TruncateTableTarget>,
3789    /// Optional partition specification
3790    pub partitions: Option<Vec<Expr>>,
3791    /// TABLE - optional keyword
3792    pub table: bool,
3793    /// Postgres-specific option: [ RESTART IDENTITY | CONTINUE IDENTITY ]
3794    pub identity: Option<super::TruncateIdentityOption>,
3795    /// Postgres-specific option: [ CASCADE | RESTRICT ]
3796    pub cascade: Option<super::CascadeOption>,
3797    /// ClickHouse-specific option: [ ON CLUSTER cluster_name ]
3798    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/truncate/)
3799    pub on_cluster: Option<Ident>,
3800}
3801
3802impl fmt::Display for Truncate {
3803    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3804        let table = if self.table { "TABLE " } else { "" };
3805
3806        write!(
3807            f,
3808            "TRUNCATE {table}{table_names}",
3809            table_names = display_comma_separated(&self.table_names)
3810        )?;
3811
3812        if let Some(identity) = &self.identity {
3813            match identity {
3814                super::TruncateIdentityOption::Restart => write!(f, " RESTART IDENTITY")?,
3815                super::TruncateIdentityOption::Continue => write!(f, " CONTINUE IDENTITY")?,
3816            }
3817        }
3818        if let Some(cascade) = &self.cascade {
3819            match cascade {
3820                super::CascadeOption::Cascade => write!(f, " CASCADE")?,
3821                super::CascadeOption::Restrict => write!(f, " RESTRICT")?,
3822            }
3823        }
3824
3825        if let Some(ref parts) = &self.partitions {
3826            if !parts.is_empty() {
3827                write!(f, " PARTITION ({})", display_comma_separated(parts))?;
3828            }
3829        }
3830        if let Some(on_cluster) = &self.on_cluster {
3831            write!(f, " ON CLUSTER {on_cluster}")?;
3832        }
3833        Ok(())
3834    }
3835}
3836
3837impl Spanned for Truncate {
3838    fn span(&self) -> Span {
3839        Span::union_iter(
3840            self.table_names.iter().map(|i| i.name.span()).chain(
3841                self.partitions
3842                    .iter()
3843                    .flat_map(|i| i.iter().map(|k| k.span())),
3844            ),
3845        )
3846    }
3847}
3848
3849/// An `MSCK` statement.
3850///
3851/// ```sql
3852/// MSCK [REPAIR] TABLE table_name [ADD|DROP|SYNC PARTITIONS]
3853/// ```
3854/// MSCK (Hive) - MetaStore Check command
3855#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3856#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3857#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3858pub struct Msck {
3859    /// Table name to check
3860    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
3861    pub table_name: ObjectName,
3862    /// Whether to repair the table
3863    pub repair: bool,
3864    /// Partition action (ADD, DROP, or SYNC)
3865    pub partition_action: Option<super::AddDropSync>,
3866}
3867
3868impl fmt::Display for Msck {
3869    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3870        write!(
3871            f,
3872            "MSCK {repair}TABLE {table}",
3873            repair = if self.repair { "REPAIR " } else { "" },
3874            table = self.table_name
3875        )?;
3876        if let Some(pa) = &self.partition_action {
3877            write!(f, " {pa}")?;
3878        }
3879        Ok(())
3880    }
3881}
3882
3883impl Spanned for Msck {
3884    fn span(&self) -> Span {
3885        self.table_name.span()
3886    }
3887}
3888
3889/// CREATE VIEW statement.
3890#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3891#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3892#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3893pub struct CreateView {
3894    /// True if this is a `CREATE OR ALTER VIEW` statement
3895    ///
3896    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-view-transact-sql)
3897    pub or_alter: bool,
3898    pub or_replace: bool,
3899    pub materialized: bool,
3900    /// Snowflake: SECURE view modifier
3901    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
3902    pub secure: bool,
3903    /// View name
3904    pub name: ObjectName,
3905    /// If `if_not_exists` is true, this flag is set to true if the view name comes before the `IF NOT EXISTS` clause.
3906    /// Example:
3907    /// ```sql
3908    /// CREATE VIEW myview IF NOT EXISTS AS SELECT 1`
3909    ///  ```
3910    /// Otherwise, the flag is set to false if the view name comes after the clause
3911    /// Example:
3912    /// ```sql
3913    /// CREATE VIEW IF NOT EXISTS myview AS SELECT 1`
3914    ///  ```
3915    pub name_before_not_exists: bool,
3916    pub columns: Vec<ViewColumnDef>,
3917    pub query: Box<Query>,
3918    pub options: CreateTableOptions,
3919    pub cluster_by: Vec<Ident>,
3920    /// Snowflake: Views can have comments in Snowflake.
3921    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
3922    pub comment: Option<String>,
3923    /// if true, has RedShift [`WITH NO SCHEMA BINDING`] clause <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_VIEW.html>
3924    pub with_no_schema_binding: bool,
3925    /// if true, has SQLite `IF NOT EXISTS` clause <https://www.sqlite.org/lang_createview.html>
3926    pub if_not_exists: bool,
3927    /// if true, has SQLite `TEMP` or `TEMPORARY` clause <https://www.sqlite.org/lang_createview.html>
3928    pub temporary: bool,
3929    /// if not None, has Clickhouse `TO` clause, specify the table into which to insert results
3930    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/view#materialized-view>
3931    pub to: Option<ObjectName>,
3932    /// MySQL: Optional parameters for the view algorithm, definer, and security context
3933    pub params: Option<CreateViewParams>,
3934}
3935
3936impl fmt::Display for CreateView {
3937    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3938        write!(
3939            f,
3940            "CREATE {or_alter}{or_replace}",
3941            or_alter = if self.or_alter { "OR ALTER " } else { "" },
3942            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
3943        )?;
3944        if let Some(ref params) = self.params {
3945            params.fmt(f)?;
3946        }
3947        write!(
3948            f,
3949            "{secure}{materialized}{temporary}VIEW {if_not_and_name}{to}",
3950            if_not_and_name = if self.if_not_exists {
3951                if self.name_before_not_exists {
3952                    format!("{} IF NOT EXISTS", self.name)
3953                } else {
3954                    format!("IF NOT EXISTS {}", self.name)
3955                }
3956            } else {
3957                format!("{}", self.name)
3958            },
3959            secure = if self.secure { "SECURE " } else { "" },
3960            materialized = if self.materialized {
3961                "MATERIALIZED "
3962            } else {
3963                ""
3964            },
3965            temporary = if self.temporary { "TEMPORARY " } else { "" },
3966            to = self
3967                .to
3968                .as_ref()
3969                .map(|to| format!(" TO {to}"))
3970                .unwrap_or_default()
3971        )?;
3972        if !self.columns.is_empty() {
3973            write!(f, " ({})", display_comma_separated(&self.columns))?;
3974        }
3975        if matches!(self.options, CreateTableOptions::With(_)) {
3976            write!(f, " {}", self.options)?;
3977        }
3978        if let Some(ref comment) = self.comment {
3979            write!(f, " COMMENT = '{}'", escape_single_quote_string(comment))?;
3980        }
3981        if !self.cluster_by.is_empty() {
3982            write!(
3983                f,
3984                " CLUSTER BY ({})",
3985                display_comma_separated(&self.cluster_by)
3986            )?;
3987        }
3988        if matches!(self.options, CreateTableOptions::Options(_)) {
3989            write!(f, " {}", self.options)?;
3990        }
3991        f.write_str(" AS")?;
3992        SpaceOrNewline.fmt(f)?;
3993        self.query.fmt(f)?;
3994        if self.with_no_schema_binding {
3995            write!(f, " WITH NO SCHEMA BINDING")?;
3996        }
3997        Ok(())
3998    }
3999}
4000
4001/// CREATE EXTENSION statement
4002/// Note: this is a PostgreSQL-specific statement
4003#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4004#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4005#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4006pub struct CreateExtension {
4007    pub name: Ident,
4008    pub if_not_exists: bool,
4009    pub cascade: bool,
4010    pub schema: Option<Ident>,
4011    pub version: Option<Ident>,
4012}
4013
4014impl fmt::Display for CreateExtension {
4015    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4016        write!(
4017            f,
4018            "CREATE EXTENSION {if_not_exists}{name}",
4019            if_not_exists = if self.if_not_exists {
4020                "IF NOT EXISTS "
4021            } else {
4022                ""
4023            },
4024            name = self.name
4025        )?;
4026        if self.cascade || self.schema.is_some() || self.version.is_some() {
4027            write!(f, " WITH")?;
4028
4029            if let Some(name) = &self.schema {
4030                write!(f, " SCHEMA {name}")?;
4031            }
4032            if let Some(version) = &self.version {
4033                write!(f, " VERSION {version}")?;
4034            }
4035            if self.cascade {
4036                write!(f, " CASCADE")?;
4037            }
4038        }
4039
4040        Ok(())
4041    }
4042}
4043
4044impl Spanned for CreateExtension {
4045    fn span(&self) -> Span {
4046        Span::empty()
4047    }
4048}
4049
4050/// DROP EXTENSION statement  
4051/// Note: this is a PostgreSQL-specific statement
4052///
4053/// # References
4054///
4055/// PostgreSQL Documentation:
4056/// <https://www.postgresql.org/docs/current/sql-dropextension.html>
4057#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4058#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4059#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4060pub struct DropExtension {
4061    pub names: Vec<Ident>,
4062    pub if_exists: bool,
4063    /// `CASCADE` or `RESTRICT`
4064    pub cascade_or_restrict: Option<ReferentialAction>,
4065}
4066
4067impl fmt::Display for DropExtension {
4068    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4069        write!(f, "DROP EXTENSION")?;
4070        if self.if_exists {
4071            write!(f, " IF EXISTS")?;
4072        }
4073        write!(f, " {}", display_comma_separated(&self.names))?;
4074        if let Some(cascade_or_restrict) = &self.cascade_or_restrict {
4075            write!(f, " {cascade_or_restrict}")?;
4076        }
4077        Ok(())
4078    }
4079}
4080
4081impl Spanned for DropExtension {
4082    fn span(&self) -> Span {
4083        Span::empty()
4084    }
4085}
4086
4087/// Table type for ALTER TABLE statements.
4088/// Used to distinguish between regular tables, Iceberg tables, and Dynamic tables.
4089#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4090#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4091#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4092pub enum AlterTableType {
4093    /// Iceberg table type
4094    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
4095    Iceberg,
4096    /// Dynamic table type
4097    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
4098    Dynamic,
4099}
4100
4101/// ALTER TABLE statement
4102#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4103#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4104#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4105pub struct AlterTable {
4106    /// Table name
4107    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
4108    pub name: ObjectName,
4109    pub if_exists: bool,
4110    pub only: bool,
4111    pub operations: Vec<AlterTableOperation>,
4112    pub location: Option<HiveSetLocation>,
4113    /// ClickHouse dialect supports `ON CLUSTER` clause for ALTER TABLE
4114    /// For example: `ALTER TABLE table_name ON CLUSTER cluster_name ADD COLUMN c UInt32`
4115    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/update)
4116    pub on_cluster: Option<Ident>,
4117    /// Table type: None for regular tables, Some(AlterTableType) for Iceberg or Dynamic tables
4118    pub table_type: Option<AlterTableType>,
4119    /// Token that represents the end of the statement (semicolon or EOF)
4120    pub end_token: AttachedToken,
4121}
4122
4123impl fmt::Display for AlterTable {
4124    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4125        match &self.table_type {
4126            Some(AlterTableType::Iceberg) => write!(f, "ALTER ICEBERG TABLE ")?,
4127            Some(AlterTableType::Dynamic) => write!(f, "ALTER DYNAMIC TABLE ")?,
4128            None => write!(f, "ALTER TABLE ")?,
4129        }
4130
4131        if self.if_exists {
4132            write!(f, "IF EXISTS ")?;
4133        }
4134        if self.only {
4135            write!(f, "ONLY ")?;
4136        }
4137        write!(f, "{} ", &self.name)?;
4138        if let Some(cluster) = &self.on_cluster {
4139            write!(f, "ON CLUSTER {cluster} ")?;
4140        }
4141        write!(f, "{}", display_comma_separated(&self.operations))?;
4142        if let Some(loc) = &self.location {
4143            write!(f, " {loc}")?
4144        }
4145        Ok(())
4146    }
4147}
4148
4149/// DROP FUNCTION statement
4150#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4151#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4152#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4153pub struct DropFunction {
4154    pub if_exists: bool,
4155    /// One or more functions to drop
4156    pub func_desc: Vec<FunctionDesc>,
4157    /// `CASCADE` or `RESTRICT`
4158    pub drop_behavior: Option<DropBehavior>,
4159}
4160
4161impl fmt::Display for DropFunction {
4162    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4163        write!(
4164            f,
4165            "DROP FUNCTION{} {}",
4166            if self.if_exists { " IF EXISTS" } else { "" },
4167            display_comma_separated(&self.func_desc),
4168        )?;
4169        if let Some(op) = &self.drop_behavior {
4170            write!(f, " {op}")?;
4171        }
4172        Ok(())
4173    }
4174}
4175
4176impl Spanned for DropFunction {
4177    fn span(&self) -> Span {
4178        Span::empty()
4179    }
4180}
4181
4182/// CREATE OPERATOR statement
4183/// See <https://www.postgresql.org/docs/current/sql-createoperator.html>
4184#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4185#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4186#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4187pub struct CreateOperator {
4188    /// Operator name (can be schema-qualified)
4189    pub name: ObjectName,
4190    /// FUNCTION or PROCEDURE parameter (function name)
4191    pub function: ObjectName,
4192    /// Whether PROCEDURE keyword was used (vs FUNCTION)
4193    pub is_procedure: bool,
4194    /// LEFTARG parameter (left operand type)
4195    pub left_arg: Option<DataType>,
4196    /// RIGHTARG parameter (right operand type)
4197    pub right_arg: Option<DataType>,
4198    /// Operator options (COMMUTATOR, NEGATOR, RESTRICT, JOIN, HASHES, MERGES)
4199    pub options: Vec<OperatorOption>,
4200}
4201
4202/// CREATE OPERATOR FAMILY statement
4203/// See <https://www.postgresql.org/docs/current/sql-createopfamily.html>
4204#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4205#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4206#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4207pub struct CreateOperatorFamily {
4208    /// Operator family name (can be schema-qualified)
4209    pub name: ObjectName,
4210    /// Index method (btree, hash, gist, gin, etc.)
4211    pub using: Ident,
4212}
4213
4214/// CREATE OPERATOR CLASS statement
4215/// See <https://www.postgresql.org/docs/current/sql-createopclass.html>
4216#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4217#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4218#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4219pub struct CreateOperatorClass {
4220    /// Operator class name (can be schema-qualified)
4221    pub name: ObjectName,
4222    /// Whether this is the default operator class for the type
4223    pub default: bool,
4224    /// The data type
4225    pub for_type: DataType,
4226    /// Index method (btree, hash, gist, gin, etc.)
4227    pub using: Ident,
4228    /// Optional operator family name
4229    pub family: Option<ObjectName>,
4230    /// List of operator class items (operators, functions, storage)
4231    pub items: Vec<OperatorClassItem>,
4232}
4233
4234impl fmt::Display for CreateOperator {
4235    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4236        write!(f, "CREATE OPERATOR {} (", self.name)?;
4237
4238        let function_keyword = if self.is_procedure {
4239            "PROCEDURE"
4240        } else {
4241            "FUNCTION"
4242        };
4243        let mut params = vec![format!("{} = {}", function_keyword, self.function)];
4244
4245        if let Some(left_arg) = &self.left_arg {
4246            params.push(format!("LEFTARG = {}", left_arg));
4247        }
4248        if let Some(right_arg) = &self.right_arg {
4249            params.push(format!("RIGHTARG = {}", right_arg));
4250        }
4251
4252        for option in &self.options {
4253            params.push(option.to_string());
4254        }
4255
4256        write!(f, "{}", params.join(", "))?;
4257        write!(f, ")")
4258    }
4259}
4260
4261impl fmt::Display for CreateOperatorFamily {
4262    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4263        write!(
4264            f,
4265            "CREATE OPERATOR FAMILY {} USING {}",
4266            self.name, self.using
4267        )
4268    }
4269}
4270
4271impl fmt::Display for CreateOperatorClass {
4272    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4273        write!(f, "CREATE OPERATOR CLASS {}", self.name)?;
4274        if self.default {
4275            write!(f, " DEFAULT")?;
4276        }
4277        write!(f, " FOR TYPE {} USING {}", self.for_type, self.using)?;
4278        if let Some(family) = &self.family {
4279            write!(f, " FAMILY {}", family)?;
4280        }
4281        write!(f, " AS {}", display_comma_separated(&self.items))
4282    }
4283}
4284
4285/// Operator argument types for CREATE OPERATOR CLASS
4286#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4287#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4288#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4289pub struct OperatorArgTypes {
4290    pub left: DataType,
4291    pub right: DataType,
4292}
4293
4294impl fmt::Display for OperatorArgTypes {
4295    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4296        write!(f, "{}, {}", self.left, self.right)
4297    }
4298}
4299
4300/// An item in a CREATE OPERATOR CLASS statement
4301#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4302#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4303#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4304pub enum OperatorClassItem {
4305    /// OPERATOR clause
4306    Operator {
4307        strategy_number: u32,
4308        operator_name: ObjectName,
4309        /// Optional operator argument types
4310        op_types: Option<OperatorArgTypes>,
4311        /// FOR SEARCH or FOR ORDER BY
4312        purpose: Option<OperatorPurpose>,
4313    },
4314    /// FUNCTION clause
4315    Function {
4316        support_number: u32,
4317        /// Optional function argument types for the operator class
4318        op_types: Option<Vec<DataType>>,
4319        function_name: ObjectName,
4320        /// Function argument types
4321        argument_types: Vec<DataType>,
4322    },
4323    /// STORAGE clause
4324    Storage { storage_type: DataType },
4325}
4326
4327/// Purpose of an operator in an operator class
4328#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4329#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4330#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4331pub enum OperatorPurpose {
4332    ForSearch,
4333    ForOrderBy { sort_family: ObjectName },
4334}
4335
4336impl fmt::Display for OperatorClassItem {
4337    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4338        match self {
4339            OperatorClassItem::Operator {
4340                strategy_number,
4341                operator_name,
4342                op_types,
4343                purpose,
4344            } => {
4345                write!(f, "OPERATOR {strategy_number} {operator_name}")?;
4346                if let Some(types) = op_types {
4347                    write!(f, " ({types})")?;
4348                }
4349                if let Some(purpose) = purpose {
4350                    write!(f, " {purpose}")?;
4351                }
4352                Ok(())
4353            }
4354            OperatorClassItem::Function {
4355                support_number,
4356                op_types,
4357                function_name,
4358                argument_types,
4359            } => {
4360                write!(f, "FUNCTION {support_number}")?;
4361                if let Some(types) = op_types {
4362                    write!(f, " ({})", display_comma_separated(types))?;
4363                }
4364                write!(f, " {function_name}")?;
4365                if !argument_types.is_empty() {
4366                    write!(f, "({})", display_comma_separated(argument_types))?;
4367                }
4368                Ok(())
4369            }
4370            OperatorClassItem::Storage { storage_type } => {
4371                write!(f, "STORAGE {storage_type}")
4372            }
4373        }
4374    }
4375}
4376
4377impl fmt::Display for OperatorPurpose {
4378    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4379        match self {
4380            OperatorPurpose::ForSearch => write!(f, "FOR SEARCH"),
4381            OperatorPurpose::ForOrderBy { sort_family } => {
4382                write!(f, "FOR ORDER BY {sort_family}")
4383            }
4384        }
4385    }
4386}
4387
4388/// `DROP OPERATOR` statement
4389/// See <https://www.postgresql.org/docs/current/sql-dropoperator.html>
4390#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4391#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4392#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4393pub struct DropOperator {
4394    /// `IF EXISTS` clause
4395    pub if_exists: bool,
4396    /// One or more operators to drop with their signatures
4397    pub operators: Vec<DropOperatorSignature>,
4398    /// `CASCADE or RESTRICT`
4399    pub drop_behavior: Option<DropBehavior>,
4400}
4401
4402/// Operator signature for a `DROP OPERATOR` statement
4403#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4404#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4405#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4406pub struct DropOperatorSignature {
4407    /// Operator name
4408    pub name: ObjectName,
4409    /// Left operand type
4410    pub left_type: Option<DataType>,
4411    /// Right operand type
4412    pub right_type: DataType,
4413}
4414
4415impl fmt::Display for DropOperatorSignature {
4416    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4417        write!(f, "{} (", self.name)?;
4418        if let Some(left_type) = &self.left_type {
4419            write!(f, "{}", left_type)?;
4420        } else {
4421            write!(f, "NONE")?;
4422        }
4423        write!(f, ", {})", self.right_type)
4424    }
4425}
4426
4427impl fmt::Display for DropOperator {
4428    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4429        write!(f, "DROP OPERATOR")?;
4430        if self.if_exists {
4431            write!(f, " IF EXISTS")?;
4432        }
4433        write!(f, " {}", display_comma_separated(&self.operators))?;
4434        if let Some(drop_behavior) = &self.drop_behavior {
4435            write!(f, " {}", drop_behavior)?;
4436        }
4437        Ok(())
4438    }
4439}
4440
4441impl Spanned for DropOperator {
4442    fn span(&self) -> Span {
4443        Span::empty()
4444    }
4445}
4446
4447/// `DROP OPERATOR FAMILY` statement
4448/// See <https://www.postgresql.org/docs/current/sql-dropopfamily.html>
4449#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4450#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4451#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4452pub struct DropOperatorFamily {
4453    /// `IF EXISTS` clause
4454    pub if_exists: bool,
4455    /// One or more operator families to drop
4456    pub names: Vec<ObjectName>,
4457    /// Index method (btree, hash, gist, gin, etc.)
4458    pub using: Ident,
4459    /// `CASCADE or RESTRICT`
4460    pub drop_behavior: Option<DropBehavior>,
4461}
4462
4463impl fmt::Display for DropOperatorFamily {
4464    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4465        write!(f, "DROP OPERATOR FAMILY")?;
4466        if self.if_exists {
4467            write!(f, " IF EXISTS")?;
4468        }
4469        write!(f, " {}", display_comma_separated(&self.names))?;
4470        write!(f, " USING {}", self.using)?;
4471        if let Some(drop_behavior) = &self.drop_behavior {
4472            write!(f, " {}", drop_behavior)?;
4473        }
4474        Ok(())
4475    }
4476}
4477
4478impl Spanned for DropOperatorFamily {
4479    fn span(&self) -> Span {
4480        Span::empty()
4481    }
4482}
4483
4484/// `DROP OPERATOR CLASS` statement
4485/// See <https://www.postgresql.org/docs/current/sql-dropopclass.html>
4486#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4487#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4488#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4489pub struct DropOperatorClass {
4490    /// `IF EXISTS` clause
4491    pub if_exists: bool,
4492    /// One or more operator classes to drop
4493    pub names: Vec<ObjectName>,
4494    /// Index method (btree, hash, gist, gin, etc.)
4495    pub using: Ident,
4496    /// `CASCADE or RESTRICT`
4497    pub drop_behavior: Option<DropBehavior>,
4498}
4499
4500impl fmt::Display for DropOperatorClass {
4501    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4502        write!(f, "DROP OPERATOR CLASS")?;
4503        if self.if_exists {
4504            write!(f, " IF EXISTS")?;
4505        }
4506        write!(f, " {}", display_comma_separated(&self.names))?;
4507        write!(f, " USING {}", self.using)?;
4508        if let Some(drop_behavior) = &self.drop_behavior {
4509            write!(f, " {}", drop_behavior)?;
4510        }
4511        Ok(())
4512    }
4513}
4514
4515impl Spanned for DropOperatorClass {
4516    fn span(&self) -> Span {
4517        Span::empty()
4518    }
4519}