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