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