Skip to main content

sqlparser/ast/
ddl.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! AST types specific to CREATE/ALTER variants of [`Statement`](crate::ast::Statement)
19//! (commonly referred to as Data Definition Language, or DDL)
20
21#[cfg(not(feature = "std"))]
22use alloc::{
23    boxed::Box,
24    format,
25    string::{String, ToString},
26    vec,
27    vec::Vec,
28};
29use core::fmt::{self, Display, Write};
30
31#[cfg(feature = "serde")]
32use serde::{Deserialize, Serialize};
33
34#[cfg(feature = "visitor")]
35use sqlparser_derive::{Visit, VisitMut};
36
37use crate::ast::value::escape_single_quote_string;
38use crate::ast::{
39    display_comma_separated, display_separated,
40    table_constraints::{
41        CheckConstraint, ForeignKeyConstraint, PrimaryKeyConstraint, TableConstraint,
42        UniqueConstraint,
43    },
44    ArgMode, AttachedToken, CommentDef, ConditionalStatements, CreateFunctionBody,
45    CreateFunctionUsing, CreateTableLikeKind, CreateTableOptions, CreateViewParams, DataType, Expr,
46    FileFormat, FunctionBehavior, FunctionCalledOnNull, FunctionDefinitionSetParam, FunctionDesc,
47    FunctionDeterminismSpecifier, FunctionParallel, FunctionSecurity, HiveDistributionStyle,
48    HiveFormat, HiveIOFormat, HiveRowFormat, HiveSetLocation, Ident, InitializeKind,
49    MySQLColumnPosition, ObjectName, OnCommit, OneOrManyWithParens, OperateFunctionArg,
50    OrderByExpr, ProjectionSelect, Query, RefreshModeKind, ResetConfig, RowAccessPolicy,
51    SequenceOptions, Spanned, SqlOption, StorageLifecyclePolicy, StorageSerializationPolicy,
52    TableVersion, Tag, TriggerEvent, TriggerExecBody, TriggerObject, TriggerPeriod,
53    TriggerReferencing, Value, ValueWithSpan, WrappedCollection,
54};
55use crate::display_utils::{DisplayCommaSeparated, Indent, NewLine, SpaceOrNewline};
56use crate::keywords::Keyword;
57use crate::tokenizer::{Span, Token};
58
59/// Index column type.
60#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
61#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
62#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
63pub struct IndexColumn {
64    /// The indexed column expression.
65    pub column: OrderByExpr,
66    /// Optional operator class (index operator name).
67    pub operator_class: Option<ObjectName>,
68}
69
70impl From<Ident> for IndexColumn {
71    fn from(c: Ident) -> Self {
72        Self {
73            column: OrderByExpr::from(c),
74            operator_class: None,
75        }
76    }
77}
78
79impl<'a> From<&'a str> for IndexColumn {
80    fn from(c: &'a str) -> Self {
81        let ident = Ident::new(c);
82        ident.into()
83    }
84}
85
86impl fmt::Display for IndexColumn {
87    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88        write!(f, "{}", self.column)?;
89        if let Some(operator_class) = &self.operator_class {
90            write!(f, " {operator_class}")?;
91        }
92        Ok(())
93    }
94}
95
96/// ALTER TABLE operation REPLICA IDENTITY values
97/// See [Postgres ALTER TABLE docs](https://www.postgresql.org/docs/current/sql-altertable.html)
98#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
99#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
100#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
101pub enum ReplicaIdentity {
102    /// No replica identity (`REPLICA IDENTITY NOTHING`).
103    Nothing,
104    /// Full replica identity (`REPLICA IDENTITY FULL`).
105    Full,
106    /// Default replica identity (`REPLICA IDENTITY DEFAULT`).
107    Default,
108    /// Use the given index as replica identity (`REPLICA IDENTITY USING INDEX`).
109    Index(Ident),
110}
111
112impl fmt::Display for ReplicaIdentity {
113    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114        match self {
115            ReplicaIdentity::Nothing => f.write_str("NOTHING"),
116            ReplicaIdentity::Full => f.write_str("FULL"),
117            ReplicaIdentity::Default => f.write_str("DEFAULT"),
118            ReplicaIdentity::Index(idx) => write!(f, "USING INDEX {idx}"),
119        }
120    }
121}
122
123/// An `ALTER TABLE` (`Statement::AlterTable`) operation
124#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
125#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
126#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
127pub enum AlterTableOperation {
128    /// `ADD <table_constraint> [NOT VALID]`
129    AddConstraint {
130        /// The table constraint to add.
131        constraint: TableConstraint,
132        /// Whether the constraint should be marked `NOT VALID`.
133        not_valid: bool,
134    },
135    /// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
136    AddColumn {
137        /// `[COLUMN]`.
138        column_keyword: bool,
139        /// `[IF NOT EXISTS]`
140        if_not_exists: bool,
141        /// <column_def>.
142        column_def: ColumnDef,
143        /// MySQL `ALTER TABLE` only  [FIRST | AFTER column_name]
144        column_position: Option<MySQLColumnPosition>,
145    },
146    /// `ADD PROJECTION [IF NOT EXISTS] name ( SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY])`
147    ///
148    /// Note: this is a ClickHouse-specific operation.
149    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#add-projection)
150    AddProjection {
151        /// Whether `IF NOT EXISTS` was specified.
152        if_not_exists: bool,
153        /// Name of the projection to add.
154        name: Ident,
155        /// The projection's select clause.
156        select: ProjectionSelect,
157    },
158    /// `DROP PROJECTION [IF EXISTS] name`
159    ///
160    /// Note: this is a ClickHouse-specific operation.
161    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#drop-projection)
162    DropProjection {
163        /// Whether `IF EXISTS` was specified.
164        if_exists: bool,
165        /// Name of the projection to drop.
166        name: Ident,
167    },
168    /// `MATERIALIZE PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
169    ///
170    ///  Note: this is a ClickHouse-specific operation.
171    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#materialize-projection)
172    MaterializeProjection {
173        /// Whether `IF EXISTS` was specified.
174        if_exists: bool,
175        /// Name of the projection to materialize.
176        name: Ident,
177        /// Optional partition name to operate on.
178        partition: Option<Ident>,
179    },
180    /// `CLEAR PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
181    ///
182    /// Note: this is a ClickHouse-specific operation.
183    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#clear-projection)
184    ClearProjection {
185        /// Whether `IF EXISTS` was specified.
186        if_exists: bool,
187        /// Name of the projection to clear.
188        name: Ident,
189        /// Optional partition name to operate on.
190        partition: Option<Ident>,
191    },
192    /// `DISABLE ROW LEVEL SECURITY`
193    ///
194    /// Note: this is a PostgreSQL-specific operation.
195    /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
196    DisableRowLevelSecurity,
197    /// `DISABLE RULE rewrite_rule_name`
198    ///
199    /// Note: this is a PostgreSQL-specific operation.
200    DisableRule {
201        /// Name of the rule to disable.
202        name: Ident,
203    },
204    /// `DISABLE TRIGGER [ trigger_name | ALL | USER ]`
205    ///
206    /// Note: this is a PostgreSQL-specific operation.
207    DisableTrigger {
208        /// Name of the trigger to disable (or ALL/USER).
209        name: Ident,
210    },
211    /// `DROP CONSTRAINT [ IF EXISTS ] <name>`
212    DropConstraint {
213        /// `IF EXISTS` flag for dropping the constraint.
214        if_exists: bool,
215        /// Name of the constraint to drop.
216        name: Ident,
217        /// Optional drop behavior (`CASCADE`/`RESTRICT`).
218        drop_behavior: Option<DropBehavior>,
219    },
220    /// `DROP [ COLUMN ] [ IF EXISTS ] <column_name> [ , <column_name>, ... ] [ CASCADE ]`
221    DropColumn {
222        /// Whether the `COLUMN` keyword was present.
223        has_column_keyword: bool,
224        /// Names of columns to drop.
225        column_names: Vec<Ident>,
226        /// Whether `IF EXISTS` was specified for the columns.
227        if_exists: bool,
228        /// Optional drop behavior for the column removal.
229        drop_behavior: Option<DropBehavior>,
230    },
231    /// `ATTACH PART|PARTITION <partition_expr>`
232    /// Note: this is a ClickHouse-specific operation, please refer to
233    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
234    AttachPartition {
235        // PART is not a short form of PARTITION, it's a separate keyword
236        // which represents a physical file on disk and partition is a logical entity.
237        /// Partition expression to attach.
238        partition: Partition,
239    },
240    /// `DETACH PART|PARTITION <partition_expr>`
241    /// Note: this is a ClickHouse-specific operation, please refer to
242    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#detach-partitionpart)
243    DetachPartition {
244        // See `AttachPartition` for more details
245        /// Partition expression to detach.
246        partition: Partition,
247    },
248    /// `FREEZE PARTITION <partition_expr>`
249    /// Note: this is a ClickHouse-specific operation, please refer to
250    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#freeze-partition)
251    FreezePartition {
252        /// Partition to freeze.
253        partition: Partition,
254        /// Optional name for the freeze operation.
255        with_name: Option<Ident>,
256    },
257    /// `UNFREEZE PARTITION <partition_expr>`
258    /// Note: this is a ClickHouse-specific operation, please refer to
259    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#unfreeze-partition)
260    UnfreezePartition {
261        /// Partition to unfreeze.
262        partition: Partition,
263        /// Optional name associated with the unfreeze operation.
264        with_name: Option<Ident>,
265    },
266    /// `DROP PRIMARY KEY`
267    ///
268    /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/alter-table.html)
269    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constraints-drop)
270    DropPrimaryKey {
271        /// Optional drop behavior for the primary key (`CASCADE`/`RESTRICT`).
272        drop_behavior: Option<DropBehavior>,
273    },
274    /// `DROP FOREIGN KEY <fk_symbol>`
275    ///
276    /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/alter-table.html)
277    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constraints-drop)
278    DropForeignKey {
279        /// Foreign key symbol/name to drop.
280        name: Ident,
281        /// Optional drop behavior for the foreign key.
282        drop_behavior: Option<DropBehavior>,
283    },
284    /// `DROP INDEX <index_name>`
285    ///
286    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
287    DropIndex {
288        /// Name of the index to drop.
289        name: Ident,
290    },
291    /// `ENABLE ALWAYS RULE rewrite_rule_name`
292    ///
293    /// Note: this is a PostgreSQL-specific operation.
294    EnableAlwaysRule {
295        /// Name of the rule to enable.
296        name: Ident,
297    },
298    /// `ENABLE ALWAYS TRIGGER trigger_name`
299    ///
300    /// Note: this is a PostgreSQL-specific operation.
301    EnableAlwaysTrigger {
302        /// Name of the trigger to enable.
303        name: Ident,
304    },
305    /// `ENABLE REPLICA RULE rewrite_rule_name`
306    ///
307    /// Note: this is a PostgreSQL-specific operation.
308    EnableReplicaRule {
309        /// Name of the replica rule to enable.
310        name: Ident,
311    },
312    /// `ENABLE REPLICA TRIGGER trigger_name`
313    ///
314    /// Note: this is a PostgreSQL-specific operation.
315    EnableReplicaTrigger {
316        /// Name of the replica trigger to enable.
317        name: Ident,
318    },
319    /// `ENABLE ROW LEVEL SECURITY`
320    ///
321    /// Note: this is a PostgreSQL-specific operation.
322    /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
323    EnableRowLevelSecurity,
324    /// `FORCE ROW LEVEL SECURITY`
325    ///
326    /// Note: this is a PostgreSQL-specific operation.
327    /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
328    ForceRowLevelSecurity,
329    /// `NO FORCE ROW LEVEL SECURITY`
330    ///
331    /// Note: this is a PostgreSQL-specific operation.
332    /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
333    NoForceRowLevelSecurity,
334    /// `ENABLE RULE rewrite_rule_name`
335    ///
336    /// Note: this is a PostgreSQL-specific operation.
337    EnableRule {
338        /// Name of the rule to enable.
339        name: Ident,
340    },
341    /// `ENABLE TRIGGER [ trigger_name | ALL | USER ]`
342    ///
343    /// Note: this is a PostgreSQL-specific operation.
344    EnableTrigger {
345        /// Name of the trigger to enable (or ALL/USER).
346        name: Ident,
347    },
348    /// `RENAME TO PARTITION (partition=val)`
349    RenamePartitions {
350        /// Old partition expressions to be renamed.
351        old_partitions: Vec<Expr>,
352        /// New partition expressions corresponding to the old ones.
353        new_partitions: Vec<Expr>,
354    },
355    /// REPLICA IDENTITY { DEFAULT | USING INDEX index_name | FULL | NOTHING }
356    ///
357    /// Note: this is a PostgreSQL-specific operation.
358    /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
359    ReplicaIdentity {
360        /// Replica identity setting to apply.
361        identity: ReplicaIdentity,
362    },
363    /// Add Partitions
364    AddPartitions {
365        /// Whether `IF NOT EXISTS` was present when adding partitions.
366        if_not_exists: bool,
367        /// New partitions to add.
368        new_partitions: Vec<Partition>,
369    },
370    /// `DROP PARTITIONS ...` / drop partitions from the table.
371    DropPartitions {
372        /// Partitions to drop (expressions).
373        partitions: Vec<Expr>,
374        /// Whether `IF EXISTS` was specified for dropping partitions.
375        if_exists: bool,
376    },
377    /// `RENAME [ COLUMN ] <old_column_name> TO <new_column_name>`
378    RenameColumn {
379        /// Existing column name to rename.
380        old_column_name: Ident,
381        /// New column name.
382        new_column_name: Ident,
383    },
384    /// `RENAME TO <table_name>`
385    RenameTable {
386        /// The new table name or renaming kind.
387        table_name: RenameTableNameKind,
388    },
389    // CHANGE [ COLUMN ] <old_name> <new_name> <data_type> [ <options> ]
390    /// Change an existing column's name, type, and options.
391    ChangeColumn {
392        /// Old column name.
393        old_name: Ident,
394        /// New column name.
395        new_name: Ident,
396        /// New data type for the column.
397        data_type: DataType,
398        /// Column options to apply after the change.
399        options: Vec<ColumnOption>,
400        /// MySQL-specific column position (`FIRST`/`AFTER`).
401        column_position: Option<MySQLColumnPosition>,
402    },
403    // CHANGE [ COLUMN ] <col_name> <data_type> [ <options> ]
404    /// Modify an existing column's type and options.
405    ModifyColumn {
406        /// Column name to modify.
407        col_name: Ident,
408        /// New data type for the column.
409        data_type: DataType,
410        /// Column options to set.
411        options: Vec<ColumnOption>,
412        /// MySQL-specific column position (`FIRST`/`AFTER`).
413        column_position: Option<MySQLColumnPosition>,
414    },
415    /// `RENAME CONSTRAINT <old_constraint_name> TO <new_constraint_name>`
416    ///
417    /// Note: this is a PostgreSQL-specific operation.
418    /// Rename a constraint on the table.
419    RenameConstraint {
420        /// Existing constraint name.
421        old_name: Ident,
422        /// New constraint name.
423        new_name: Ident,
424    },
425    /// `ALTER [ COLUMN ]`
426    /// Alter a specific column with the provided operation.
427    AlterColumn {
428        /// The column to alter.
429        column_name: Ident,
430        /// Operation to apply to the column.
431        op: AlterColumnOperation,
432    },
433    /// 'SWAP WITH <table_name>'
434    ///
435    /// Note: this is Snowflake specific <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
436    SwapWith {
437        /// Table name to swap with.
438        table_name: ObjectName,
439    },
440    /// 'SET TBLPROPERTIES ( { property_key [ = ] property_val } [, ...] )'
441    SetTblProperties {
442        /// Table properties specified as SQL options.
443        table_properties: Vec<SqlOption>,
444    },
445    /// `OWNER TO { <new_owner> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
446    ///
447    /// Note: this is PostgreSQL-specific <https://www.postgresql.org/docs/current/sql-altertable.html>
448    OwnerTo {
449        /// The new owner to assign to the table.
450        new_owner: Owner,
451    },
452    /// Snowflake table clustering options
453    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-table#clustering-actions-clusteringaction>
454    ClusterBy {
455        /// Expressions used for clustering the table.
456        exprs: Vec<Expr>,
457    },
458    /// Remove the clustering key from the table.
459    DropClusteringKey,
460    /// Redshift `ALTER SORTKEY (column_list)`
461    /// <https://docs.aws.amazon.com/redshift/latest/dg/r_ALTER_TABLE.html>
462    AlterSortKey {
463        /// Column references in the sort key.
464        columns: Vec<Expr>,
465    },
466    /// Suspend background reclustering operations.
467    SuspendRecluster,
468    /// Resume background reclustering operations.
469    ResumeRecluster,
470    /// `REFRESH [ '<subpath>' ]`
471    ///
472    /// Note: this is Snowflake specific for dynamic/external tables
473    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-dynamic-table>
474    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
475    Refresh {
476        /// Optional subpath for external table refresh
477        subpath: Option<String>,
478    },
479    /// `SUSPEND`
480    ///
481    /// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
482    Suspend,
483    /// `RESUME`
484    ///
485    /// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
486    Resume,
487    /// `ALGORITHM [=] { DEFAULT | INSTANT | INPLACE | COPY }`
488    ///
489    /// [MySQL]-specific table alter algorithm.
490    ///
491    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
492    Algorithm {
493        /// Whether the `=` sign was used (`ALGORITHM = ...`).
494        equals: bool,
495        /// The algorithm to use for the alter operation (MySQL-specific).
496        algorithm: AlterTableAlgorithm,
497    },
498
499    /// `LOCK [=] { DEFAULT | NONE | SHARED | EXCLUSIVE }`
500    ///
501    /// [MySQL]-specific table alter lock.
502    ///
503    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
504    Lock {
505        /// Whether the `=` sign was used (`LOCK = ...`).
506        equals: bool,
507        /// The locking behavior to apply (MySQL-specific).
508        lock: AlterTableLock,
509    },
510    /// `AUTO_INCREMENT [=] <value>`
511    ///
512    /// [MySQL]-specific table option for raising current auto increment value.
513    ///
514    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
515    AutoIncrement {
516        /// Whether the `=` sign was used (`AUTO_INCREMENT = ...`).
517        equals: bool,
518        /// Value to set for the auto-increment counter.
519        value: ValueWithSpan,
520    },
521    /// `VALIDATE CONSTRAINT <name>`
522    ValidateConstraint {
523        /// Name of the constraint to validate.
524        name: Ident,
525    },
526    /// Arbitrary parenthesized `SET` options.
527    ///
528    /// Example:
529    /// ```sql
530    /// SET (scale_factor = 0.01, threshold = 500)`
531    /// ```
532    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-altertable.html)
533    SetOptionsParens {
534        /// Parenthesized options supplied to `SET (...)`.
535        options: Vec<SqlOption>,
536    },
537}
538
539/// An `ALTER Policy` (`Statement::AlterPolicy`) operation
540///
541/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
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 AlterPolicyOperation {
546    /// Rename the policy to `new_name`.
547    Rename {
548        /// The new identifier for the policy.
549        new_name: Ident,
550    },
551    /// Apply/modify policy properties.
552    Apply {
553        /// Optional list of owners the policy applies to.
554        to: Option<Vec<Owner>>,
555        /// Optional `USING` expression for the policy.
556        using: Option<Expr>,
557        /// Optional `WITH CHECK` expression for the policy.
558        with_check: Option<Expr>,
559    },
560}
561
562impl fmt::Display for AlterPolicyOperation {
563    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
564        match self {
565            AlterPolicyOperation::Rename { new_name } => {
566                write!(f, " RENAME TO {new_name}")
567            }
568            AlterPolicyOperation::Apply {
569                to,
570                using,
571                with_check,
572            } => {
573                if let Some(to) = to {
574                    write!(f, " TO {}", display_comma_separated(to))?;
575                }
576                if let Some(using) = using {
577                    write!(f, " USING ({using})")?;
578                }
579                if let Some(with_check) = with_check {
580                    write!(f, " WITH CHECK ({with_check})")?;
581                }
582                Ok(())
583            }
584        }
585    }
586}
587
588/// [MySQL] `ALTER TABLE` algorithm.
589///
590/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
591#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
592#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
593#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
594/// Algorithm option for `ALTER TABLE` operations (MySQL-specific).
595pub enum AlterTableAlgorithm {
596    /// Default algorithm selection.
597    Default,
598    /// `INSTANT` algorithm.
599    Instant,
600    /// `INPLACE` algorithm.
601    Inplace,
602    /// `COPY` algorithm.
603    Copy,
604}
605
606impl fmt::Display for AlterTableAlgorithm {
607    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
608        f.write_str(match self {
609            Self::Default => "DEFAULT",
610            Self::Instant => "INSTANT",
611            Self::Inplace => "INPLACE",
612            Self::Copy => "COPY",
613        })
614    }
615}
616
617/// [MySQL] `ALTER TABLE` lock.
618///
619/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
620#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
621#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
622#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
623/// Locking behavior for `ALTER TABLE` (MySQL-specific).
624pub enum AlterTableLock {
625    /// `DEFAULT` lock behavior.
626    Default,
627    /// `NONE` lock.
628    None,
629    /// `SHARED` lock.
630    Shared,
631    /// `EXCLUSIVE` lock.
632    Exclusive,
633}
634
635impl fmt::Display for AlterTableLock {
636    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
637        f.write_str(match self {
638            Self::Default => "DEFAULT",
639            Self::None => "NONE",
640            Self::Shared => "SHARED",
641            Self::Exclusive => "EXCLUSIVE",
642        })
643    }
644}
645
646#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
647#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
648#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
649/// New owner specification for `ALTER TABLE ... OWNER TO ...`
650pub enum Owner {
651    /// A specific user/role identifier.
652    Ident(Ident),
653    /// `CURRENT_ROLE` keyword.
654    CurrentRole,
655    /// `CURRENT_USER` keyword.
656    CurrentUser,
657    /// `SESSION_USER` keyword.
658    SessionUser,
659}
660
661impl fmt::Display for Owner {
662    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
663        match self {
664            Owner::Ident(ident) => write!(f, "{ident}"),
665            Owner::CurrentRole => write!(f, "CURRENT_ROLE"),
666            Owner::CurrentUser => write!(f, "CURRENT_USER"),
667            Owner::SessionUser => write!(f, "SESSION_USER"),
668        }
669    }
670}
671
672#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
673#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
674#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
675/// New connector owner specification for `ALTER CONNECTOR ... OWNER TO ...`
676pub enum AlterConnectorOwner {
677    /// `USER <ident>` connector owner.
678    User(Ident),
679    /// `ROLE <ident>` connector owner.
680    Role(Ident),
681}
682
683impl fmt::Display for AlterConnectorOwner {
684    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
685        match self {
686            AlterConnectorOwner::User(ident) => write!(f, "USER {ident}"),
687            AlterConnectorOwner::Role(ident) => write!(f, "ROLE {ident}"),
688        }
689    }
690}
691
692#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
693#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
694#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
695/// Alterations that can be applied to an index.
696pub enum AlterIndexOperation {
697    /// Rename the index to `index_name`.
698    RenameIndex {
699        /// The new name for the index.
700        index_name: ObjectName,
701    },
702}
703
704impl fmt::Display for AlterTableOperation {
705    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
706        match self {
707            AlterTableOperation::AddPartitions {
708                if_not_exists,
709                new_partitions,
710            } => write!(
711                f,
712                "ADD{ine} {}",
713                display_separated(new_partitions, " "),
714                ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
715            ),
716            AlterTableOperation::AddConstraint {
717                not_valid,
718                constraint,
719            } => {
720                write!(f, "ADD {constraint}")?;
721                if *not_valid {
722                    write!(f, " NOT VALID")?;
723                }
724                Ok(())
725            }
726            AlterTableOperation::AddColumn {
727                column_keyword,
728                if_not_exists,
729                column_def,
730                column_position,
731            } => {
732                write!(f, "ADD")?;
733                if *column_keyword {
734                    write!(f, " COLUMN")?;
735                }
736                if *if_not_exists {
737                    write!(f, " IF NOT EXISTS")?;
738                }
739                write!(f, " {column_def}")?;
740
741                if let Some(position) = column_position {
742                    write!(f, " {position}")?;
743                }
744
745                Ok(())
746            }
747            AlterTableOperation::AddProjection {
748                if_not_exists,
749                name,
750                select: query,
751            } => {
752                write!(f, "ADD PROJECTION")?;
753                if *if_not_exists {
754                    write!(f, " IF NOT EXISTS")?;
755                }
756                write!(f, " {name} ({query})")
757            }
758            AlterTableOperation::Algorithm { equals, algorithm } => {
759                write!(
760                    f,
761                    "ALGORITHM {}{}",
762                    if *equals { "= " } else { "" },
763                    algorithm
764                )
765            }
766            AlterTableOperation::DropProjection { if_exists, name } => {
767                write!(f, "DROP PROJECTION")?;
768                if *if_exists {
769                    write!(f, " IF EXISTS")?;
770                }
771                write!(f, " {name}")
772            }
773            AlterTableOperation::MaterializeProjection {
774                if_exists,
775                name,
776                partition,
777            } => {
778                write!(f, "MATERIALIZE PROJECTION")?;
779                if *if_exists {
780                    write!(f, " IF EXISTS")?;
781                }
782                write!(f, " {name}")?;
783                if let Some(partition) = partition {
784                    write!(f, " IN PARTITION {partition}")?;
785                }
786                Ok(())
787            }
788            AlterTableOperation::ClearProjection {
789                if_exists,
790                name,
791                partition,
792            } => {
793                write!(f, "CLEAR PROJECTION")?;
794                if *if_exists {
795                    write!(f, " IF EXISTS")?;
796                }
797                write!(f, " {name}")?;
798                if let Some(partition) = partition {
799                    write!(f, " IN PARTITION {partition}")?;
800                }
801                Ok(())
802            }
803            AlterTableOperation::AlterColumn { column_name, op } => {
804                write!(f, "ALTER COLUMN {column_name} {op}")
805            }
806            AlterTableOperation::DisableRowLevelSecurity => {
807                write!(f, "DISABLE ROW LEVEL SECURITY")
808            }
809            AlterTableOperation::DisableRule { name } => {
810                write!(f, "DISABLE RULE {name}")
811            }
812            AlterTableOperation::DisableTrigger { name } => {
813                write!(f, "DISABLE TRIGGER {name}")
814            }
815            AlterTableOperation::DropPartitions {
816                partitions,
817                if_exists,
818            } => write!(
819                f,
820                "DROP{ie} PARTITION ({})",
821                display_comma_separated(partitions),
822                ie = if *if_exists { " IF EXISTS" } else { "" }
823            ),
824            AlterTableOperation::DropConstraint {
825                if_exists,
826                name,
827                drop_behavior,
828            } => {
829                write!(
830                    f,
831                    "DROP CONSTRAINT {}{}",
832                    if *if_exists { "IF EXISTS " } else { "" },
833                    name
834                )?;
835                if let Some(drop_behavior) = drop_behavior {
836                    write!(f, " {drop_behavior}")?;
837                }
838                Ok(())
839            }
840            AlterTableOperation::DropPrimaryKey { drop_behavior } => {
841                write!(f, "DROP PRIMARY KEY")?;
842                if let Some(drop_behavior) = drop_behavior {
843                    write!(f, " {drop_behavior}")?;
844                }
845                Ok(())
846            }
847            AlterTableOperation::DropForeignKey {
848                name,
849                drop_behavior,
850            } => {
851                write!(f, "DROP FOREIGN KEY {name}")?;
852                if let Some(drop_behavior) = drop_behavior {
853                    write!(f, " {drop_behavior}")?;
854                }
855                Ok(())
856            }
857            AlterTableOperation::DropIndex { name } => write!(f, "DROP INDEX {name}"),
858            AlterTableOperation::DropColumn {
859                has_column_keyword,
860                column_names: column_name,
861                if_exists,
862                drop_behavior,
863            } => {
864                write!(
865                    f,
866                    "DROP {}{}{}",
867                    if *has_column_keyword { "COLUMN " } else { "" },
868                    if *if_exists { "IF EXISTS " } else { "" },
869                    display_comma_separated(column_name),
870                )?;
871                if let Some(drop_behavior) = drop_behavior {
872                    write!(f, " {drop_behavior}")?;
873                }
874                Ok(())
875            }
876            AlterTableOperation::AttachPartition { partition } => {
877                write!(f, "ATTACH {partition}")
878            }
879            AlterTableOperation::DetachPartition { partition } => {
880                write!(f, "DETACH {partition}")
881            }
882            AlterTableOperation::EnableAlwaysRule { name } => {
883                write!(f, "ENABLE ALWAYS RULE {name}")
884            }
885            AlterTableOperation::EnableAlwaysTrigger { name } => {
886                write!(f, "ENABLE ALWAYS TRIGGER {name}")
887            }
888            AlterTableOperation::EnableReplicaRule { name } => {
889                write!(f, "ENABLE REPLICA RULE {name}")
890            }
891            AlterTableOperation::EnableReplicaTrigger { name } => {
892                write!(f, "ENABLE REPLICA TRIGGER {name}")
893            }
894            AlterTableOperation::EnableRowLevelSecurity => {
895                write!(f, "ENABLE ROW LEVEL SECURITY")
896            }
897            AlterTableOperation::ForceRowLevelSecurity => {
898                write!(f, "FORCE ROW LEVEL SECURITY")
899            }
900            AlterTableOperation::NoForceRowLevelSecurity => {
901                write!(f, "NO FORCE ROW LEVEL SECURITY")
902            }
903            AlterTableOperation::EnableRule { name } => {
904                write!(f, "ENABLE RULE {name}")
905            }
906            AlterTableOperation::EnableTrigger { name } => {
907                write!(f, "ENABLE TRIGGER {name}")
908            }
909            AlterTableOperation::RenamePartitions {
910                old_partitions,
911                new_partitions,
912            } => write!(
913                f,
914                "PARTITION ({}) RENAME TO PARTITION ({})",
915                display_comma_separated(old_partitions),
916                display_comma_separated(new_partitions)
917            ),
918            AlterTableOperation::RenameColumn {
919                old_column_name,
920                new_column_name,
921            } => write!(f, "RENAME COLUMN {old_column_name} TO {new_column_name}"),
922            AlterTableOperation::RenameTable { table_name } => {
923                write!(f, "RENAME {table_name}")
924            }
925            AlterTableOperation::ChangeColumn {
926                old_name,
927                new_name,
928                data_type,
929                options,
930                column_position,
931            } => {
932                write!(f, "CHANGE COLUMN {old_name} {new_name} {data_type}")?;
933                if !options.is_empty() {
934                    write!(f, " {}", display_separated(options, " "))?;
935                }
936                if let Some(position) = column_position {
937                    write!(f, " {position}")?;
938                }
939
940                Ok(())
941            }
942            AlterTableOperation::ModifyColumn {
943                col_name,
944                data_type,
945                options,
946                column_position,
947            } => {
948                write!(f, "MODIFY COLUMN {col_name} {data_type}")?;
949                if !options.is_empty() {
950                    write!(f, " {}", display_separated(options, " "))?;
951                }
952                if let Some(position) = column_position {
953                    write!(f, " {position}")?;
954                }
955
956                Ok(())
957            }
958            AlterTableOperation::RenameConstraint { old_name, new_name } => {
959                write!(f, "RENAME CONSTRAINT {old_name} TO {new_name}")
960            }
961            AlterTableOperation::SwapWith { table_name } => {
962                write!(f, "SWAP WITH {table_name}")
963            }
964            AlterTableOperation::OwnerTo { new_owner } => {
965                write!(f, "OWNER TO {new_owner}")
966            }
967            AlterTableOperation::SetTblProperties { table_properties } => {
968                write!(
969                    f,
970                    "SET TBLPROPERTIES({})",
971                    display_comma_separated(table_properties)
972                )
973            }
974            AlterTableOperation::FreezePartition {
975                partition,
976                with_name,
977            } => {
978                write!(f, "FREEZE {partition}")?;
979                if let Some(name) = with_name {
980                    write!(f, " WITH NAME {name}")?;
981                }
982                Ok(())
983            }
984            AlterTableOperation::UnfreezePartition {
985                partition,
986                with_name,
987            } => {
988                write!(f, "UNFREEZE {partition}")?;
989                if let Some(name) = with_name {
990                    write!(f, " WITH NAME {name}")?;
991                }
992                Ok(())
993            }
994            AlterTableOperation::ClusterBy { exprs } => {
995                write!(f, "CLUSTER BY ({})", display_comma_separated(exprs))?;
996                Ok(())
997            }
998            AlterTableOperation::DropClusteringKey => {
999                write!(f, "DROP CLUSTERING KEY")?;
1000                Ok(())
1001            }
1002            AlterTableOperation::AlterSortKey { columns } => {
1003                write!(f, "ALTER SORTKEY({})", display_comma_separated(columns))?;
1004                Ok(())
1005            }
1006            AlterTableOperation::SuspendRecluster => {
1007                write!(f, "SUSPEND RECLUSTER")?;
1008                Ok(())
1009            }
1010            AlterTableOperation::ResumeRecluster => {
1011                write!(f, "RESUME RECLUSTER")?;
1012                Ok(())
1013            }
1014            AlterTableOperation::Refresh { subpath } => {
1015                write!(f, "REFRESH")?;
1016                if let Some(path) = subpath {
1017                    write!(f, " '{path}'")?;
1018                }
1019                Ok(())
1020            }
1021            AlterTableOperation::Suspend => {
1022                write!(f, "SUSPEND")
1023            }
1024            AlterTableOperation::Resume => {
1025                write!(f, "RESUME")
1026            }
1027            AlterTableOperation::AutoIncrement { equals, value } => {
1028                write!(
1029                    f,
1030                    "AUTO_INCREMENT {}{}",
1031                    if *equals { "= " } else { "" },
1032                    value
1033                )
1034            }
1035            AlterTableOperation::Lock { equals, lock } => {
1036                write!(f, "LOCK {}{}", if *equals { "= " } else { "" }, lock)
1037            }
1038            AlterTableOperation::ReplicaIdentity { identity } => {
1039                write!(f, "REPLICA IDENTITY {identity}")
1040            }
1041            AlterTableOperation::ValidateConstraint { name } => {
1042                write!(f, "VALIDATE CONSTRAINT {name}")
1043            }
1044            AlterTableOperation::SetOptionsParens { options } => {
1045                write!(f, "SET ({})", display_comma_separated(options))
1046            }
1047        }
1048    }
1049}
1050
1051impl fmt::Display for AlterIndexOperation {
1052    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1053        match self {
1054            AlterIndexOperation::RenameIndex { index_name } => {
1055                write!(f, "RENAME TO {index_name}")
1056            }
1057        }
1058    }
1059}
1060
1061/// An `ALTER TYPE` statement (`Statement::AlterType`)
1062#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1063#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1064#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1065pub struct AlterType {
1066    /// Name of the type being altered (may be schema-qualified).
1067    pub name: ObjectName,
1068    /// The specific alteration operation to perform.
1069    pub operation: AlterTypeOperation,
1070}
1071
1072/// An [AlterType] operation
1073#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1074#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1075#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1076pub enum AlterTypeOperation {
1077    /// Rename the type.
1078    Rename(AlterTypeRename),
1079    /// Add a new value to the type (for enum-like types).
1080    AddValue(AlterTypeAddValue),
1081    /// Rename an existing value of the type.
1082    RenameValue(AlterTypeRenameValue),
1083}
1084
1085/// See [AlterTypeOperation::Rename]
1086#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1087#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1088#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1089pub struct AlterTypeRename {
1090    /// The new name for the type.
1091    pub new_name: Ident,
1092}
1093
1094/// See [AlterTypeOperation::AddValue]
1095#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1096#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1097#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1098pub struct AlterTypeAddValue {
1099    /// If true, do not error when the value already exists (`IF NOT EXISTS`).
1100    pub if_not_exists: bool,
1101    /// The identifier for the new value to add.
1102    pub value: Ident,
1103    /// Optional relative position for the new value (`BEFORE` / `AFTER`).
1104    pub position: Option<AlterTypeAddValuePosition>,
1105}
1106
1107/// See [AlterTypeAddValue]
1108#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1109#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1110#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1111pub enum AlterTypeAddValuePosition {
1112    /// Place the new value before the given neighbor value.
1113    Before(Ident),
1114    /// Place the new value after the given neighbor value.
1115    After(Ident),
1116}
1117
1118/// See [AlterTypeOperation::RenameValue]
1119#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1120#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1121#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1122pub struct AlterTypeRenameValue {
1123    /// Existing value identifier to rename.
1124    pub from: Ident,
1125    /// New identifier for the value.
1126    pub to: Ident,
1127}
1128
1129impl fmt::Display for AlterTypeOperation {
1130    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1131        match self {
1132            Self::Rename(AlterTypeRename { new_name }) => {
1133                write!(f, "RENAME TO {new_name}")
1134            }
1135            Self::AddValue(AlterTypeAddValue {
1136                if_not_exists,
1137                value,
1138                position,
1139            }) => {
1140                write!(f, "ADD VALUE")?;
1141                if *if_not_exists {
1142                    write!(f, " IF NOT EXISTS")?;
1143                }
1144                write!(f, " {value}")?;
1145                match position {
1146                    Some(AlterTypeAddValuePosition::Before(neighbor_value)) => {
1147                        write!(f, " BEFORE {neighbor_value}")?;
1148                    }
1149                    Some(AlterTypeAddValuePosition::After(neighbor_value)) => {
1150                        write!(f, " AFTER {neighbor_value}")?;
1151                    }
1152                    None => {}
1153                };
1154                Ok(())
1155            }
1156            Self::RenameValue(AlterTypeRenameValue { from, to }) => {
1157                write!(f, "RENAME VALUE {from} TO {to}")
1158            }
1159        }
1160    }
1161}
1162
1163/// `ALTER OPERATOR` statement
1164/// See <https://www.postgresql.org/docs/current/sql-alteroperator.html>
1165#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1166#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1167#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1168pub struct AlterOperator {
1169    /// Operator name (can be schema-qualified)
1170    pub name: ObjectName,
1171    /// Left operand type (`None` if no left operand)
1172    pub left_type: Option<DataType>,
1173    /// Right operand type
1174    pub right_type: DataType,
1175    /// The operation to perform
1176    pub operation: AlterOperatorOperation,
1177}
1178
1179/// An [AlterOperator] operation
1180#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1181#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1182#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1183pub enum AlterOperatorOperation {
1184    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
1185    OwnerTo(Owner),
1186    /// `SET SCHEMA new_schema`
1187    /// Set the operator's schema name.
1188    SetSchema {
1189        /// New schema name for the operator
1190        schema_name: ObjectName,
1191    },
1192    /// `SET ( options )`
1193    Set {
1194        /// List of operator options to set
1195        options: Vec<OperatorOption>,
1196    },
1197}
1198
1199/// Option for `ALTER OPERATOR SET` operation
1200#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1201#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1202#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1203pub enum OperatorOption {
1204    /// `RESTRICT = { res_proc | NONE }`
1205    Restrict(Option<ObjectName>),
1206    /// `JOIN = { join_proc | NONE }`
1207    Join(Option<ObjectName>),
1208    /// `COMMUTATOR = com_op`
1209    Commutator(ObjectName),
1210    /// `NEGATOR = neg_op`
1211    Negator(ObjectName),
1212    /// `HASHES`
1213    Hashes,
1214    /// `MERGES`
1215    Merges,
1216}
1217
1218impl fmt::Display for AlterOperator {
1219    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1220        write!(f, "ALTER OPERATOR {} (", self.name)?;
1221        if let Some(left_type) = &self.left_type {
1222            write!(f, "{}", left_type)?;
1223        } else {
1224            write!(f, "NONE")?;
1225        }
1226        write!(f, ", {}) {}", self.right_type, self.operation)
1227    }
1228}
1229
1230impl fmt::Display for AlterOperatorOperation {
1231    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1232        match self {
1233            Self::OwnerTo(owner) => write!(f, "OWNER TO {}", owner),
1234            Self::SetSchema { schema_name } => write!(f, "SET SCHEMA {}", schema_name),
1235            Self::Set { options } => {
1236                write!(f, "SET (")?;
1237                for (i, option) in options.iter().enumerate() {
1238                    if i > 0 {
1239                        write!(f, ", ")?;
1240                    }
1241                    write!(f, "{}", option)?;
1242                }
1243                write!(f, ")")
1244            }
1245        }
1246    }
1247}
1248
1249impl fmt::Display for OperatorOption {
1250    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1251        match self {
1252            Self::Restrict(Some(proc_name)) => write!(f, "RESTRICT = {}", proc_name),
1253            Self::Restrict(None) => write!(f, "RESTRICT = NONE"),
1254            Self::Join(Some(proc_name)) => write!(f, "JOIN = {}", proc_name),
1255            Self::Join(None) => write!(f, "JOIN = NONE"),
1256            Self::Commutator(op_name) => write!(f, "COMMUTATOR = {}", op_name),
1257            Self::Negator(op_name) => write!(f, "NEGATOR = {}", op_name),
1258            Self::Hashes => write!(f, "HASHES"),
1259            Self::Merges => write!(f, "MERGES"),
1260        }
1261    }
1262}
1263
1264/// An `ALTER COLUMN` (`Statement::AlterTable`) operation
1265#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1266#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1267#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1268pub enum AlterColumnOperation {
1269    /// `SET NOT NULL`
1270    SetNotNull,
1271    /// `DROP NOT NULL`
1272    DropNotNull,
1273    /// `SET DEFAULT <expr>`
1274    /// Set the column default value.
1275    SetDefault {
1276        /// Expression representing the new default value.
1277        value: Expr,
1278    },
1279    /// `DROP DEFAULT`
1280    DropDefault,
1281    /// `[SET DATA] TYPE <data_type> [USING <expr>]`
1282    SetDataType {
1283        /// Target data type for the column.
1284        data_type: DataType,
1285        /// PostgreSQL-specific `USING <expr>` expression for conversion.
1286        using: Option<Expr>,
1287        /// Set to true if the statement includes the `SET DATA TYPE` keywords.
1288        had_set: bool,
1289    },
1290
1291    /// `ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]`
1292    ///
1293    /// Note: this is a PostgreSQL-specific operation.
1294    AddGenerated {
1295        /// Optional `GENERATED AS` specifier (e.g. `ALWAYS` or `BY DEFAULT`).
1296        generated_as: Option<GeneratedAs>,
1297        /// Optional sequence options for identity generation.
1298        sequence_options: Option<Vec<SequenceOptions>>,
1299    },
1300}
1301
1302impl fmt::Display for AlterColumnOperation {
1303    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1304        match self {
1305            AlterColumnOperation::SetNotNull => write!(f, "SET NOT NULL",),
1306            AlterColumnOperation::DropNotNull => write!(f, "DROP NOT NULL",),
1307            AlterColumnOperation::SetDefault { value } => {
1308                write!(f, "SET DEFAULT {value}")
1309            }
1310            AlterColumnOperation::DropDefault => {
1311                write!(f, "DROP DEFAULT")
1312            }
1313            AlterColumnOperation::SetDataType {
1314                data_type,
1315                using,
1316                had_set,
1317            } => {
1318                if *had_set {
1319                    write!(f, "SET DATA ")?;
1320                }
1321                write!(f, "TYPE {data_type}")?;
1322                if let Some(expr) = using {
1323                    write!(f, " USING {expr}")?;
1324                }
1325                Ok(())
1326            }
1327            AlterColumnOperation::AddGenerated {
1328                generated_as,
1329                sequence_options,
1330            } => {
1331                let generated_as = match generated_as {
1332                    Some(GeneratedAs::Always) => " ALWAYS",
1333                    Some(GeneratedAs::ByDefault) => " BY DEFAULT",
1334                    _ => "",
1335                };
1336
1337                write!(f, "ADD GENERATED{generated_as} AS IDENTITY",)?;
1338                if let Some(options) = sequence_options {
1339                    write!(f, " (")?;
1340
1341                    for sequence_option in options {
1342                        write!(f, "{sequence_option}")?;
1343                    }
1344
1345                    write!(f, " )")?;
1346                }
1347                Ok(())
1348            }
1349        }
1350    }
1351}
1352
1353/// Representation whether a definition can can contains the KEY or INDEX keywords with the same
1354/// meaning.
1355///
1356/// This enum initially is directed to `FULLTEXT`,`SPATIAL`, and `UNIQUE` indexes on create table
1357/// statements of `MySQL` [(1)].
1358///
1359/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1360#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1361#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1362#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1363pub enum KeyOrIndexDisplay {
1364    /// Nothing to display
1365    None,
1366    /// Display the KEY keyword
1367    Key,
1368    /// Display the INDEX keyword
1369    Index,
1370}
1371
1372impl KeyOrIndexDisplay {
1373    /// Check if this is the `None` variant.
1374    pub fn is_none(self) -> bool {
1375        matches!(self, Self::None)
1376    }
1377}
1378
1379impl fmt::Display for KeyOrIndexDisplay {
1380    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1381        let left_space = matches!(f.align(), Some(fmt::Alignment::Right));
1382
1383        if left_space && !self.is_none() {
1384            f.write_char(' ')?
1385        }
1386
1387        match self {
1388            KeyOrIndexDisplay::None => {
1389                write!(f, "")
1390            }
1391            KeyOrIndexDisplay::Key => {
1392                write!(f, "KEY")
1393            }
1394            KeyOrIndexDisplay::Index => {
1395                write!(f, "INDEX")
1396            }
1397        }
1398    }
1399}
1400
1401/// Indexing method used by that index.
1402///
1403/// This structure isn't present on ANSI, but is found at least in [`MySQL` CREATE TABLE][1],
1404/// [`MySQL` CREATE INDEX][2], and [Postgresql CREATE INDEX][3] statements.
1405///
1406/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1407/// [2]: https://dev.mysql.com/doc/refman/8.0/en/create-index.html
1408/// [3]: https://www.postgresql.org/docs/14/sql-createindex.html
1409#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1410#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1411#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1412pub enum IndexType {
1413    /// B-Tree index (commonly default for many databases).
1414    BTree,
1415    /// Hash index.
1416    Hash,
1417    /// Generalized Inverted Index (GIN).
1418    GIN,
1419    /// Generalized Search Tree (GiST) index.
1420    GiST,
1421    /// Space-partitioned GiST (SPGiST) index.
1422    SPGiST,
1423    /// Block Range Index (BRIN).
1424    BRIN,
1425    /// Bloom filter based index.
1426    Bloom,
1427    /// Users may define their own index types, which would
1428    /// not be covered by the above variants.
1429    Custom(Ident),
1430}
1431
1432impl fmt::Display for IndexType {
1433    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1434        match self {
1435            Self::BTree => write!(f, "BTREE"),
1436            Self::Hash => write!(f, "HASH"),
1437            Self::GIN => write!(f, "GIN"),
1438            Self::GiST => write!(f, "GIST"),
1439            Self::SPGiST => write!(f, "SPGIST"),
1440            Self::BRIN => write!(f, "BRIN"),
1441            Self::Bloom => write!(f, "BLOOM"),
1442            Self::Custom(name) => write!(f, "{name}"),
1443        }
1444    }
1445}
1446
1447/// MySQL index option, used in [`CREATE TABLE`], [`CREATE INDEX`], and [`ALTER TABLE`].
1448///
1449/// [`CREATE TABLE`]: https://dev.mysql.com/doc/refman/8.4/en/create-table.html
1450/// [`CREATE INDEX`]: https://dev.mysql.com/doc/refman/8.4/en/create-index.html
1451/// [`ALTER TABLE`]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
1452#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1453#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1454#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1455pub enum IndexOption {
1456    /// `USING { BTREE | HASH }`: Index type to use for the index.
1457    ///
1458    /// Note that we permissively parse non-MySQL index types, like `GIN`.
1459    Using(IndexType),
1460    /// `COMMENT 'string'`: Specifies a comment for the index.
1461    Comment(String),
1462}
1463
1464impl fmt::Display for IndexOption {
1465    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1466        match self {
1467            Self::Using(index_type) => write!(f, "USING {index_type}"),
1468            Self::Comment(s) => write!(f, "COMMENT '{s}'"),
1469        }
1470    }
1471}
1472
1473/// [PostgreSQL] unique index nulls handling option: `[ NULLS [ NOT ] DISTINCT ]`
1474///
1475/// [PostgreSQL]: https://www.postgresql.org/docs/17/sql-altertable.html
1476#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1477#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1478#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1479pub enum NullsDistinctOption {
1480    /// Not specified
1481    None,
1482    /// NULLS DISTINCT
1483    Distinct,
1484    /// NULLS NOT DISTINCT
1485    NotDistinct,
1486}
1487
1488impl fmt::Display for NullsDistinctOption {
1489    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1490        match self {
1491            Self::None => Ok(()),
1492            Self::Distinct => write!(f, " NULLS DISTINCT"),
1493            Self::NotDistinct => write!(f, " NULLS NOT DISTINCT"),
1494        }
1495    }
1496}
1497
1498#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1499#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1500#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1501/// A parameter of a stored procedure or function declaration.
1502pub struct ProcedureParam {
1503    /// Parameter name.
1504    pub name: Ident,
1505    /// Parameter data type.
1506    pub data_type: DataType,
1507    /// Optional mode (`IN`, `OUT`, `INOUT`, etc.).
1508    pub mode: Option<ArgMode>,
1509    /// Optional default expression for the parameter.
1510    pub default: Option<Expr>,
1511}
1512
1513impl fmt::Display for ProcedureParam {
1514    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1515        if let Some(mode) = &self.mode {
1516            if let Some(default) = &self.default {
1517                write!(f, "{mode} {} {} = {}", self.name, self.data_type, default)
1518            } else {
1519                write!(f, "{mode} {} {}", self.name, self.data_type)
1520            }
1521        } else if let Some(default) = &self.default {
1522            write!(f, "{} {} = {}", self.name, self.data_type, default)
1523        } else {
1524            write!(f, "{} {}", self.name, self.data_type)
1525        }
1526    }
1527}
1528
1529/// SQL column definition
1530#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1531#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1532#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1533pub struct ColumnDef {
1534    /// Column name.
1535    pub name: Ident,
1536    /// Column data type.
1537    pub data_type: DataType,
1538    /// Column options (defaults, constraints, generated, etc.).
1539    pub options: Vec<ColumnOptionDef>,
1540}
1541
1542impl fmt::Display for ColumnDef {
1543    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1544        if self.data_type == DataType::Unspecified {
1545            write!(f, "{}", self.name)?;
1546        } else {
1547            write!(f, "{} {}", self.name, self.data_type)?;
1548        }
1549        for option in &self.options {
1550            write!(f, " {option}")?;
1551        }
1552        Ok(())
1553    }
1554}
1555
1556/// Column definition specified in a `CREATE VIEW` statement.
1557///
1558/// Syntax
1559/// ```markdown
1560/// <name> [data_type][OPTIONS(option, ...)]
1561///
1562/// option: <name> = <value>
1563/// ```
1564///
1565/// Examples:
1566/// ```sql
1567/// name
1568/// age OPTIONS(description = "age column", tag = "prod")
1569/// amount COMMENT 'The total amount for the order line'
1570/// created_at DateTime64
1571/// ```
1572#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1573#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1574#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1575pub struct ViewColumnDef {
1576    /// Column identifier.
1577    pub name: Ident,
1578    /// Optional data type for the column.
1579    pub data_type: Option<DataType>,
1580    /// Optional column options (defaults, comments, etc.).
1581    pub options: Option<ColumnOptions>,
1582}
1583
1584#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1585#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1586#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1587/// Representation of how multiple `ColumnOption`s are grouped for a column.
1588pub enum ColumnOptions {
1589    /// Options separated by comma: `OPTIONS(a, b, c)`.
1590    CommaSeparated(Vec<ColumnOption>),
1591    /// Options separated by spaces: `OPTION_A OPTION_B`.
1592    SpaceSeparated(Vec<ColumnOption>),
1593}
1594
1595impl ColumnOptions {
1596    /// Get the column options as a slice.
1597    pub fn as_slice(&self) -> &[ColumnOption] {
1598        match self {
1599            ColumnOptions::CommaSeparated(options) => options.as_slice(),
1600            ColumnOptions::SpaceSeparated(options) => options.as_slice(),
1601        }
1602    }
1603}
1604
1605impl fmt::Display for ViewColumnDef {
1606    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1607        write!(f, "{}", self.name)?;
1608        if let Some(data_type) = self.data_type.as_ref() {
1609            write!(f, " {data_type}")?;
1610        }
1611        if let Some(options) = self.options.as_ref() {
1612            match options {
1613                ColumnOptions::CommaSeparated(column_options) => {
1614                    write!(f, " {}", display_comma_separated(column_options.as_slice()))?;
1615                }
1616                ColumnOptions::SpaceSeparated(column_options) => {
1617                    write!(f, " {}", display_separated(column_options.as_slice(), " "))?
1618                }
1619            }
1620        }
1621        Ok(())
1622    }
1623}
1624
1625/// An optionally-named `ColumnOption`: `[ CONSTRAINT <name> ] <column-option>`.
1626///
1627/// Note that implementations are substantially more permissive than the ANSI
1628/// specification on what order column options can be presented in, and whether
1629/// they are allowed to be named. The specification distinguishes between
1630/// constraints (NOT NULL, UNIQUE, PRIMARY KEY, and CHECK), which can be named
1631/// and can appear in any order, and other options (DEFAULT, GENERATED), which
1632/// cannot be named and must appear in a fixed order. `PostgreSQL`, however,
1633/// allows preceding any option with `CONSTRAINT <name>`, even those that are
1634/// not really constraints, like NULL and DEFAULT. MSSQL is less permissive,
1635/// allowing DEFAULT, UNIQUE, PRIMARY KEY and CHECK to be named, but not NULL or
1636/// NOT NULL constraints (the last of which is in violation of the spec).
1637///
1638/// For maximum flexibility, we don't distinguish between constraint and
1639/// non-constraint options, lumping them all together under the umbrella of
1640/// "column options," and we allow any column option to be named.
1641#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1642#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1643#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1644pub struct ColumnOptionDef {
1645    /// Optional name of the constraint.
1646    pub name: Option<Ident>,
1647    /// The actual column option (e.g. `NOT NULL`, `DEFAULT`, `GENERATED`, ...).
1648    pub option: ColumnOption,
1649}
1650
1651impl fmt::Display for ColumnOptionDef {
1652    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1653        write!(f, "{}{}", display_constraint_name(&self.name), self.option)
1654    }
1655}
1656
1657/// Identity is a column option for defining an identity or autoincrement column in a `CREATE TABLE` statement.
1658/// Syntax
1659/// ```sql
1660/// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1661/// ```
1662/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1663/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1664#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1665#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1666#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1667pub enum IdentityPropertyKind {
1668    /// An identity property declared via the `AUTOINCREMENT` key word
1669    /// Example:
1670    /// ```sql
1671    ///  AUTOINCREMENT(100, 1) NOORDER
1672    ///  AUTOINCREMENT START 100 INCREMENT 1 ORDER
1673    /// ```
1674    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1675    Autoincrement(IdentityProperty),
1676    /// An identity property declared via the `IDENTITY` key word
1677    /// Example, [MS SQL Server] or [Snowflake]:
1678    /// ```sql
1679    ///  IDENTITY(100, 1)
1680    /// ```
1681    /// [Snowflake]
1682    /// ```sql
1683    ///  IDENTITY(100, 1) ORDER
1684    ///  IDENTITY START 100 INCREMENT 1 NOORDER
1685    /// ```
1686    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1687    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1688    Identity(IdentityProperty),
1689}
1690
1691impl fmt::Display for IdentityPropertyKind {
1692    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1693        let (command, property) = match self {
1694            IdentityPropertyKind::Identity(property) => ("IDENTITY", property),
1695            IdentityPropertyKind::Autoincrement(property) => ("AUTOINCREMENT", property),
1696        };
1697        write!(f, "{command}")?;
1698        if let Some(parameters) = &property.parameters {
1699            write!(f, "{parameters}")?;
1700        }
1701        if let Some(order) = &property.order {
1702            write!(f, "{order}")?;
1703        }
1704        Ok(())
1705    }
1706}
1707
1708/// Properties for the `IDENTITY` / `AUTOINCREMENT` column option.
1709#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1710#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1711#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1712pub struct IdentityProperty {
1713    /// Optional parameters specifying seed/increment for the identity column.
1714    pub parameters: Option<IdentityPropertyFormatKind>,
1715    /// Optional ordering specifier (`ORDER` / `NOORDER`).
1716    pub order: Option<IdentityPropertyOrder>,
1717}
1718
1719/// A format of parameters of identity column.
1720///
1721/// It is [Snowflake] specific.
1722/// Syntax
1723/// ```sql
1724/// (seed , increment) | START num INCREMENT num
1725/// ```
1726/// [MS SQL Server] uses one way of representing these parameters.
1727/// Syntax
1728/// ```sql
1729/// (seed , increment)
1730/// ```
1731/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1732/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1733#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1734#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1735#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1736pub enum IdentityPropertyFormatKind {
1737    /// A parameters of identity column declared like parameters of function call
1738    /// Example:
1739    /// ```sql
1740    ///  (100, 1)
1741    /// ```
1742    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1743    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1744    FunctionCall(IdentityParameters),
1745    /// A parameters of identity column declared with keywords `START` and `INCREMENT`
1746    /// Example:
1747    /// ```sql
1748    ///  START 100 INCREMENT 1
1749    /// ```
1750    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1751    StartAndIncrement(IdentityParameters),
1752}
1753
1754impl fmt::Display for IdentityPropertyFormatKind {
1755    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1756        match self {
1757            IdentityPropertyFormatKind::FunctionCall(parameters) => {
1758                write!(f, "({}, {})", parameters.seed, parameters.increment)
1759            }
1760            IdentityPropertyFormatKind::StartAndIncrement(parameters) => {
1761                write!(
1762                    f,
1763                    " START {} INCREMENT {}",
1764                    parameters.seed, parameters.increment
1765                )
1766            }
1767        }
1768    }
1769}
1770/// Parameters specifying seed and increment for identity columns.
1771#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1772#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1773#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1774pub struct IdentityParameters {
1775    /// The initial seed expression for the identity column.
1776    pub seed: Expr,
1777    /// The increment expression for the identity column.
1778    pub increment: Expr,
1779}
1780
1781/// The identity column option specifies how values are generated for the auto-incremented column, either in increasing or decreasing order.
1782/// Syntax
1783/// ```sql
1784/// ORDER | NOORDER
1785/// ```
1786/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1787#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1788#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1789#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1790pub enum IdentityPropertyOrder {
1791    /// `ORDER` - preserve ordering for generated values (where supported).
1792    Order,
1793    /// `NOORDER` - do not enforce ordering for generated values.
1794    NoOrder,
1795}
1796
1797impl fmt::Display for IdentityPropertyOrder {
1798    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1799        match self {
1800            IdentityPropertyOrder::Order => write!(f, " ORDER"),
1801            IdentityPropertyOrder::NoOrder => write!(f, " NOORDER"),
1802        }
1803    }
1804}
1805
1806/// Column policy that identify a security policy of access to a column.
1807/// Syntax
1808/// ```sql
1809/// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1810/// [ WITH ] PROJECTION POLICY <policy_name>
1811/// ```
1812/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1813#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1814#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1815#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1816pub enum ColumnPolicy {
1817    /// `MASKING POLICY (<property>)`
1818    MaskingPolicy(ColumnPolicyProperty),
1819    /// `PROJECTION POLICY (<property>)`
1820    ProjectionPolicy(ColumnPolicyProperty),
1821}
1822
1823impl fmt::Display for ColumnPolicy {
1824    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1825        let (command, property) = match self {
1826            ColumnPolicy::MaskingPolicy(property) => ("MASKING POLICY", property),
1827            ColumnPolicy::ProjectionPolicy(property) => ("PROJECTION POLICY", property),
1828        };
1829        if property.with {
1830            write!(f, "WITH ")?;
1831        }
1832        write!(f, "{command} {}", property.policy_name)?;
1833        if let Some(using_columns) = &property.using_columns {
1834            write!(f, " USING ({})", display_comma_separated(using_columns))?;
1835        }
1836        Ok(())
1837    }
1838}
1839
1840#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1841#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1842#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1843/// Properties describing a column policy (masking or projection).
1844pub struct ColumnPolicyProperty {
1845    /// This flag indicates that the column policy option is declared using the `WITH` prefix.
1846    /// Example
1847    /// ```sql
1848    /// WITH PROJECTION POLICY sample_policy
1849    /// ```
1850    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1851    pub with: bool,
1852    /// The name of the policy to apply to the column.
1853    pub policy_name: ObjectName,
1854    /// Optional list of column identifiers referenced by the policy.
1855    pub using_columns: Option<Vec<Ident>>,
1856}
1857
1858/// Tags option of column
1859/// Syntax
1860/// ```sql
1861/// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1862/// ```
1863/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1864#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1865#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1866#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1867pub struct TagsColumnOption {
1868    /// This flag indicates that the tags option is declared using the `WITH` prefix.
1869    /// Example:
1870    /// ```sql
1871    /// WITH TAG (A = 'Tag A')
1872    /// ```
1873    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1874    pub with: bool,
1875    /// List of tags to attach to the column.
1876    pub tags: Vec<Tag>,
1877}
1878
1879impl fmt::Display for TagsColumnOption {
1880    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1881        if self.with {
1882            write!(f, "WITH ")?;
1883        }
1884        write!(f, "TAG ({})", display_comma_separated(&self.tags))?;
1885        Ok(())
1886    }
1887}
1888
1889/// `ColumnOption`s are modifiers that follow a column definition in a `CREATE
1890/// TABLE` statement.
1891#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1892#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1893#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1894pub enum ColumnOption {
1895    /// `NULL`
1896    Null,
1897    /// `NOT NULL`
1898    NotNull,
1899    /// `DEFAULT <restricted-expr>`
1900    Default(Expr),
1901
1902    /// `MATERIALIZE <expr>`
1903    /// Syntax: `b INT MATERIALIZE (a + 1)`
1904    ///
1905    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1906    Materialized(Expr),
1907    /// `EPHEMERAL [<expr>]`
1908    ///
1909    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1910    Ephemeral(Option<Expr>),
1911    /// `ALIAS <expr>`
1912    ///
1913    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1914    Alias(Expr),
1915
1916    /// `PRIMARY KEY [<constraint_characteristics>]`
1917    PrimaryKey(PrimaryKeyConstraint),
1918    /// `UNIQUE [<constraint_characteristics>]`
1919    Unique(UniqueConstraint),
1920    /// A referential integrity constraint (`REFERENCES <foreign_table> (<referred_columns>)
1921    /// [ MATCH { FULL | PARTIAL | SIMPLE } ]
1922    /// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
1923    ///   [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
1924    /// }
1925    /// [<constraint_characteristics>]
1926    /// `).
1927    ForeignKey(ForeignKeyConstraint),
1928    /// `CHECK (<expr>)`
1929    Check(CheckConstraint),
1930    /// Dialect-specific options, such as:
1931    /// - MySQL's `AUTO_INCREMENT` or SQLite's `AUTOINCREMENT`
1932    /// - ...
1933    DialectSpecific(Vec<Token>),
1934    /// `CHARACTER SET <name>` column option
1935    CharacterSet(ObjectName),
1936    /// `COLLATE <name>` column option
1937    Collation(ObjectName),
1938    /// `COMMENT '<text>'` column option
1939    Comment(String),
1940    /// `ON UPDATE <expr>` column option
1941    OnUpdate(Expr),
1942    /// `Generated`s are modifiers that follow a column definition in a `CREATE
1943    /// TABLE` statement.
1944    Generated {
1945        /// How the column is generated (e.g. `GENERATED ALWAYS`, `BY DEFAULT`, or expression-stored).
1946        generated_as: GeneratedAs,
1947        /// Sequence/identity options when generation is backed by a sequence.
1948        sequence_options: Option<Vec<SequenceOptions>>,
1949        /// Optional expression used to generate the column value.
1950        generation_expr: Option<Expr>,
1951        /// Mode of the generated expression (`VIRTUAL` or `STORED`) when `generation_expr` is present.
1952        generation_expr_mode: Option<GeneratedExpressionMode>,
1953        /// false if 'GENERATED ALWAYS' is skipped (option starts with AS)
1954        generated_keyword: bool,
1955    },
1956    /// BigQuery specific: Explicit column options in a view [1] or table [2]
1957    /// Syntax
1958    /// ```sql
1959    /// OPTIONS(description="field desc")
1960    /// ```
1961    /// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#view_column_option_list
1962    /// [2]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#column_option_list
1963    Options(Vec<SqlOption>),
1964    /// Creates an identity or an autoincrement column in a table.
1965    /// Syntax
1966    /// ```sql
1967    /// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1968    /// ```
1969    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1970    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1971    Identity(IdentityPropertyKind),
1972    /// SQLite specific: ON CONFLICT option on column definition
1973    /// <https://www.sqlite.org/lang_conflict.html>
1974    OnConflict(Keyword),
1975    /// Snowflake specific: an option of specifying security masking or projection policy to set on a column.
1976    /// Syntax:
1977    /// ```sql
1978    /// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1979    /// [ WITH ] PROJECTION POLICY <policy_name>
1980    /// ```
1981    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1982    Policy(ColumnPolicy),
1983    /// Snowflake specific: Specifies the tag name and the tag string value.
1984    /// Syntax:
1985    /// ```sql
1986    /// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1987    /// ```
1988    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1989    Tags(TagsColumnOption),
1990    /// MySQL specific: Spatial reference identifier
1991    /// Syntax:
1992    /// ```sql
1993    /// CREATE TABLE geom (g GEOMETRY NOT NULL SRID 4326);
1994    /// ```
1995    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/creating-spatial-indexes.html
1996    Srid(Box<Expr>),
1997    /// MySQL specific: Column is invisible via SELECT *
1998    /// Syntax:
1999    /// ```sql
2000    /// CREATE TABLE t (foo INT, bar INT INVISIBLE);
2001    /// ```
2002    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/invisible-columns.html
2003    Invisible,
2004}
2005
2006impl From<UniqueConstraint> for ColumnOption {
2007    fn from(c: UniqueConstraint) -> Self {
2008        ColumnOption::Unique(c)
2009    }
2010}
2011
2012impl From<PrimaryKeyConstraint> for ColumnOption {
2013    fn from(c: PrimaryKeyConstraint) -> Self {
2014        ColumnOption::PrimaryKey(c)
2015    }
2016}
2017
2018impl From<CheckConstraint> for ColumnOption {
2019    fn from(c: CheckConstraint) -> Self {
2020        ColumnOption::Check(c)
2021    }
2022}
2023impl From<ForeignKeyConstraint> for ColumnOption {
2024    fn from(fk: ForeignKeyConstraint) -> Self {
2025        ColumnOption::ForeignKey(fk)
2026    }
2027}
2028
2029impl fmt::Display for ColumnOption {
2030    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2031        use ColumnOption::*;
2032        match self {
2033            Null => write!(f, "NULL"),
2034            NotNull => write!(f, "NOT NULL"),
2035            Default(expr) => write!(f, "DEFAULT {expr}"),
2036            Materialized(expr) => write!(f, "MATERIALIZED {expr}"),
2037            Ephemeral(expr) => {
2038                if let Some(e) = expr {
2039                    write!(f, "EPHEMERAL {e}")
2040                } else {
2041                    write!(f, "EPHEMERAL")
2042                }
2043            }
2044            Alias(expr) => write!(f, "ALIAS {expr}"),
2045            PrimaryKey(constraint) => {
2046                write!(f, "PRIMARY KEY")?;
2047                if let Some(characteristics) = &constraint.characteristics {
2048                    write!(f, " {characteristics}")?;
2049                }
2050                Ok(())
2051            }
2052            Unique(constraint) => {
2053                write!(f, "UNIQUE{:>}", constraint.index_type_display)?;
2054                if let Some(characteristics) = &constraint.characteristics {
2055                    write!(f, " {characteristics}")?;
2056                }
2057                Ok(())
2058            }
2059            ForeignKey(constraint) => {
2060                write!(f, "REFERENCES {}", constraint.foreign_table)?;
2061                if !constraint.referred_columns.is_empty() {
2062                    write!(
2063                        f,
2064                        " ({})",
2065                        display_comma_separated(&constraint.referred_columns)
2066                    )?;
2067                }
2068                if let Some(match_kind) = &constraint.match_kind {
2069                    write!(f, " {match_kind}")?;
2070                }
2071                if let Some(action) = &constraint.on_delete {
2072                    write!(f, " ON DELETE {action}")?;
2073                }
2074                if let Some(action) = &constraint.on_update {
2075                    write!(f, " ON UPDATE {action}")?;
2076                }
2077                if let Some(characteristics) = &constraint.characteristics {
2078                    write!(f, " {characteristics}")?;
2079                }
2080                Ok(())
2081            }
2082            Check(constraint) => write!(f, "{constraint}"),
2083            DialectSpecific(val) => write!(f, "{}", display_separated(val, " ")),
2084            CharacterSet(n) => write!(f, "CHARACTER SET {n}"),
2085            Collation(n) => write!(f, "COLLATE {n}"),
2086            Comment(v) => write!(f, "COMMENT '{}'", escape_single_quote_string(v)),
2087            OnUpdate(expr) => write!(f, "ON UPDATE {expr}"),
2088            Generated {
2089                generated_as,
2090                sequence_options,
2091                generation_expr,
2092                generation_expr_mode,
2093                generated_keyword,
2094            } => {
2095                if let Some(expr) = generation_expr {
2096                    let modifier = match generation_expr_mode {
2097                        None => "",
2098                        Some(GeneratedExpressionMode::Virtual) => " VIRTUAL",
2099                        Some(GeneratedExpressionMode::Stored) => " STORED",
2100                    };
2101                    if *generated_keyword {
2102                        write!(f, "GENERATED ALWAYS AS ({expr}){modifier}")?;
2103                    } else {
2104                        write!(f, "AS ({expr}){modifier}")?;
2105                    }
2106                    Ok(())
2107                } else {
2108                    // Like Postgres - generated from sequence
2109                    let when = match generated_as {
2110                        GeneratedAs::Always => "ALWAYS",
2111                        GeneratedAs::ByDefault => "BY DEFAULT",
2112                        // ExpStored goes with an expression, handled above
2113                        GeneratedAs::ExpStored => "",
2114                    };
2115                    write!(f, "GENERATED {when} AS IDENTITY")?;
2116                    if sequence_options.is_some() {
2117                        let so = sequence_options.as_ref().unwrap();
2118                        if !so.is_empty() {
2119                            write!(f, " (")?;
2120                        }
2121                        for sequence_option in so {
2122                            write!(f, "{sequence_option}")?;
2123                        }
2124                        if !so.is_empty() {
2125                            write!(f, " )")?;
2126                        }
2127                    }
2128                    Ok(())
2129                }
2130            }
2131            Options(options) => {
2132                write!(f, "OPTIONS({})", display_comma_separated(options))
2133            }
2134            Identity(parameters) => {
2135                write!(f, "{parameters}")
2136            }
2137            OnConflict(keyword) => {
2138                write!(f, "ON CONFLICT {keyword:?}")?;
2139                Ok(())
2140            }
2141            Policy(parameters) => {
2142                write!(f, "{parameters}")
2143            }
2144            Tags(tags) => {
2145                write!(f, "{tags}")
2146            }
2147            Srid(srid) => {
2148                write!(f, "SRID {srid}")
2149            }
2150            Invisible => {
2151                write!(f, "INVISIBLE")
2152            }
2153        }
2154    }
2155}
2156
2157/// `GeneratedAs`s are modifiers that follow a column option in a `generated`.
2158/// 'ExpStored' is used for a column generated from an expression and stored.
2159#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
2160#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2161#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2162pub enum GeneratedAs {
2163    /// `GENERATED ALWAYS`
2164    Always,
2165    /// `GENERATED BY DEFAULT`
2166    ByDefault,
2167    /// Expression-based generated column that is stored (used internally for expression-stored columns)
2168    ExpStored,
2169}
2170
2171/// `GeneratedExpressionMode`s are modifiers that follow an expression in a `generated`.
2172/// No modifier is typically the same as Virtual.
2173#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
2174#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2175#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2176pub enum GeneratedExpressionMode {
2177    /// `VIRTUAL` generated expression
2178    Virtual,
2179    /// `STORED` generated expression
2180    Stored,
2181}
2182
2183#[must_use]
2184pub(crate) fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
2185    struct ConstraintName<'a>(&'a Option<Ident>);
2186    impl fmt::Display for ConstraintName<'_> {
2187        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2188            if let Some(name) = self.0 {
2189                write!(f, "CONSTRAINT {name} ")?;
2190            }
2191            Ok(())
2192        }
2193    }
2194    ConstraintName(name)
2195}
2196
2197/// If `option` is
2198/// * `Some(inner)` => create display struct for `"{prefix}{inner}{postfix}"`
2199/// * `_` => do nothing
2200#[must_use]
2201pub(crate) fn display_option<'a, T: fmt::Display>(
2202    prefix: &'a str,
2203    postfix: &'a str,
2204    option: &'a Option<T>,
2205) -> impl fmt::Display + 'a {
2206    struct OptionDisplay<'a, T>(&'a str, &'a str, &'a Option<T>);
2207    impl<T: fmt::Display> fmt::Display for OptionDisplay<'_, T> {
2208        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2209            if let Some(inner) = self.2 {
2210                let (prefix, postfix) = (self.0, self.1);
2211                write!(f, "{prefix}{inner}{postfix}")?;
2212            }
2213            Ok(())
2214        }
2215    }
2216    OptionDisplay(prefix, postfix, option)
2217}
2218
2219/// If `option` is
2220/// * `Some(inner)` => create display struct for `" {inner}"`
2221/// * `_` => do nothing
2222#[must_use]
2223pub(crate) fn display_option_spaced<T: fmt::Display>(option: &Option<T>) -> impl fmt::Display + '_ {
2224    display_option(" ", "", option)
2225}
2226
2227/// `<constraint_characteristics> = [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ]`
2228///
2229/// Used in UNIQUE and foreign key constraints. The individual settings may occur in any order.
2230#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Default, Eq, Ord, Hash)]
2231#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2232#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2233pub struct ConstraintCharacteristics {
2234    /// `[ DEFERRABLE | NOT DEFERRABLE ]`
2235    pub deferrable: Option<bool>,
2236    /// `[ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]`
2237    pub initially: Option<DeferrableInitial>,
2238    /// `[ ENFORCED | NOT ENFORCED ]`
2239    pub enforced: Option<bool>,
2240}
2241
2242/// Initial setting for deferrable constraints (`INITIALLY IMMEDIATE` or `INITIALLY DEFERRED`).
2243#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2244#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2245#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2246pub enum DeferrableInitial {
2247    /// `INITIALLY IMMEDIATE`
2248    Immediate,
2249    /// `INITIALLY DEFERRED`
2250    Deferred,
2251}
2252
2253impl ConstraintCharacteristics {
2254    fn deferrable_text(&self) -> Option<&'static str> {
2255        self.deferrable.map(|deferrable| {
2256            if deferrable {
2257                "DEFERRABLE"
2258            } else {
2259                "NOT DEFERRABLE"
2260            }
2261        })
2262    }
2263
2264    fn initially_immediate_text(&self) -> Option<&'static str> {
2265        self.initially
2266            .map(|initially_immediate| match initially_immediate {
2267                DeferrableInitial::Immediate => "INITIALLY IMMEDIATE",
2268                DeferrableInitial::Deferred => "INITIALLY DEFERRED",
2269            })
2270    }
2271
2272    fn enforced_text(&self) -> Option<&'static str> {
2273        self.enforced.map(
2274            |enforced| {
2275                if enforced {
2276                    "ENFORCED"
2277                } else {
2278                    "NOT ENFORCED"
2279                }
2280            },
2281        )
2282    }
2283}
2284
2285impl fmt::Display for ConstraintCharacteristics {
2286    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2287        let deferrable = self.deferrable_text();
2288        let initially_immediate = self.initially_immediate_text();
2289        let enforced = self.enforced_text();
2290
2291        match (deferrable, initially_immediate, enforced) {
2292            (None, None, None) => Ok(()),
2293            (None, None, Some(enforced)) => write!(f, "{enforced}"),
2294            (None, Some(initial), None) => write!(f, "{initial}"),
2295            (None, Some(initial), Some(enforced)) => write!(f, "{initial} {enforced}"),
2296            (Some(deferrable), None, None) => write!(f, "{deferrable}"),
2297            (Some(deferrable), None, Some(enforced)) => write!(f, "{deferrable} {enforced}"),
2298            (Some(deferrable), Some(initial), None) => write!(f, "{deferrable} {initial}"),
2299            (Some(deferrable), Some(initial), Some(enforced)) => {
2300                write!(f, "{deferrable} {initial} {enforced}")
2301            }
2302        }
2303    }
2304}
2305
2306/// `<referential_action> =
2307/// { RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT }`
2308///
2309/// Used in foreign key constraints in `ON UPDATE` and `ON DELETE` options.
2310#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2311#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2312#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2313pub enum ReferentialAction {
2314    /// `RESTRICT` - disallow action if it would break referential integrity.
2315    Restrict,
2316    /// `CASCADE` - propagate the action to referencing rows.
2317    Cascade,
2318    /// `SET NULL` - set referencing columns to NULL.
2319    SetNull,
2320    /// `NO ACTION` - no action at the time; may be deferred.
2321    NoAction,
2322    /// `SET DEFAULT` - set referencing columns to their default values.
2323    SetDefault,
2324}
2325
2326impl fmt::Display for ReferentialAction {
2327    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2328        f.write_str(match self {
2329            ReferentialAction::Restrict => "RESTRICT",
2330            ReferentialAction::Cascade => "CASCADE",
2331            ReferentialAction::SetNull => "SET NULL",
2332            ReferentialAction::NoAction => "NO ACTION",
2333            ReferentialAction::SetDefault => "SET DEFAULT",
2334        })
2335    }
2336}
2337
2338/// `<drop behavior> ::= CASCADE | RESTRICT`.
2339///
2340/// Used in `DROP` statements.
2341#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2342#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2343#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2344pub enum DropBehavior {
2345    /// `RESTRICT` - refuse to drop if there are any dependent objects.
2346    Restrict,
2347    /// `CASCADE` - automatically drop objects that depend on the object being dropped.
2348    Cascade,
2349}
2350
2351impl fmt::Display for DropBehavior {
2352    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2353        f.write_str(match self {
2354            DropBehavior::Restrict => "RESTRICT",
2355            DropBehavior::Cascade => "CASCADE",
2356        })
2357    }
2358}
2359
2360/// SQL user defined type definition
2361#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2362#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2363#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2364pub enum UserDefinedTypeRepresentation {
2365    /// Composite type: `CREATE TYPE name AS (attributes)`
2366    Composite {
2367        /// List of attributes for the composite type.
2368        attributes: Vec<UserDefinedTypeCompositeAttributeDef>,
2369    },
2370    /// Enum type: `CREATE TYPE name AS ENUM (labels)`
2371    ///
2372    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2373    /// Enum type: `CREATE TYPE name AS ENUM (labels)`
2374    Enum {
2375        /// Labels that make up the enum type.
2376        labels: Vec<Ident>,
2377    },
2378    /// Range type: `CREATE TYPE name AS RANGE (options)`
2379    ///
2380    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2381    Range {
2382        /// Options for the range type definition.
2383        options: Vec<UserDefinedTypeRangeOption>,
2384    },
2385    /// Base type (SQL definition): `CREATE TYPE name (options)`
2386    ///
2387    /// Note the lack of `AS` keyword
2388    ///
2389    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2390    SqlDefinition {
2391        /// Options for SQL definition of the user-defined type.
2392        options: Vec<UserDefinedTypeSqlDefinitionOption>,
2393    },
2394}
2395
2396impl fmt::Display for UserDefinedTypeRepresentation {
2397    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2398        match self {
2399            Self::Composite { attributes } => {
2400                write!(f, "AS ({})", display_comma_separated(attributes))
2401            }
2402            Self::Enum { labels } => {
2403                write!(f, "AS ENUM ({})", display_comma_separated(labels))
2404            }
2405            Self::Range { options } => {
2406                write!(f, "AS RANGE ({})", display_comma_separated(options))
2407            }
2408            Self::SqlDefinition { options } => {
2409                write!(f, "({})", display_comma_separated(options))
2410            }
2411        }
2412    }
2413}
2414
2415/// SQL user defined type attribute definition
2416#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2417#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2418#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2419pub struct UserDefinedTypeCompositeAttributeDef {
2420    /// Attribute name.
2421    pub name: Ident,
2422    /// Attribute data type.
2423    pub data_type: DataType,
2424    /// Optional collation for the attribute.
2425    pub collation: Option<ObjectName>,
2426}
2427
2428impl fmt::Display for UserDefinedTypeCompositeAttributeDef {
2429    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2430        write!(f, "{} {}", self.name, self.data_type)?;
2431        if let Some(collation) = &self.collation {
2432            write!(f, " COLLATE {collation}")?;
2433        }
2434        Ok(())
2435    }
2436}
2437
2438/// Internal length specification for PostgreSQL user-defined base types.
2439///
2440/// Specifies the internal length in bytes of the new type's internal representation.
2441/// The default assumption is that it is variable-length.
2442///
2443/// # PostgreSQL Documentation
2444/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2445///
2446/// # Examples
2447/// ```sql
2448/// CREATE TYPE mytype (
2449///     INPUT = in_func,
2450///     OUTPUT = out_func,
2451///     INTERNALLENGTH = 16  -- Fixed 16-byte length
2452/// );
2453///
2454/// CREATE TYPE mytype2 (
2455///     INPUT = in_func,
2456///     OUTPUT = out_func,
2457///     INTERNALLENGTH = VARIABLE  -- Variable length
2458/// );
2459/// ```
2460#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2461#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2462#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2463pub enum UserDefinedTypeInternalLength {
2464    /// Fixed internal length: `INTERNALLENGTH = <number>`
2465    Fixed(u64),
2466    /// Variable internal length: `INTERNALLENGTH = VARIABLE`
2467    Variable,
2468}
2469
2470impl fmt::Display for UserDefinedTypeInternalLength {
2471    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2472        match self {
2473            UserDefinedTypeInternalLength::Fixed(n) => write!(f, "{}", n),
2474            UserDefinedTypeInternalLength::Variable => write!(f, "VARIABLE"),
2475        }
2476    }
2477}
2478
2479/// Alignment specification for PostgreSQL user-defined base types.
2480///
2481/// Specifies the storage alignment requirement for values of the data type.
2482/// The allowed values equate to alignment on 1, 2, 4, or 8 byte boundaries.
2483/// Note that variable-length types must have an alignment of at least 4, since
2484/// they necessarily contain an int4 as their first component.
2485///
2486/// # PostgreSQL Documentation
2487/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2488///
2489/// # Examples
2490/// ```sql
2491/// CREATE TYPE mytype (
2492///     INPUT = in_func,
2493///     OUTPUT = out_func,
2494///     ALIGNMENT = int4  -- 4-byte alignment
2495/// );
2496/// ```
2497#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2498#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2499#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2500pub enum Alignment {
2501    /// Single-byte alignment: `ALIGNMENT = char`
2502    Char,
2503    /// 2-byte alignment: `ALIGNMENT = int2`
2504    Int2,
2505    /// 4-byte alignment: `ALIGNMENT = int4`
2506    Int4,
2507    /// 8-byte alignment: `ALIGNMENT = double`
2508    Double,
2509}
2510
2511impl fmt::Display for Alignment {
2512    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2513        match self {
2514            Alignment::Char => write!(f, "char"),
2515            Alignment::Int2 => write!(f, "int2"),
2516            Alignment::Int4 => write!(f, "int4"),
2517            Alignment::Double => write!(f, "double"),
2518        }
2519    }
2520}
2521
2522/// Storage specification for PostgreSQL user-defined base types.
2523///
2524/// Specifies the storage strategy for values of the data type:
2525/// - `plain`: Prevents compression and out-of-line storage (for fixed-length types)
2526/// - `external`: Allows out-of-line storage but not compression
2527/// - `extended`: Allows both compression and out-of-line storage (default for most types)
2528/// - `main`: Allows compression but discourages out-of-line storage
2529///
2530/// # PostgreSQL Documentation
2531/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2532///
2533/// # Examples
2534/// ```sql
2535/// CREATE TYPE mytype (
2536///     INPUT = in_func,
2537///     OUTPUT = out_func,
2538///     STORAGE = plain
2539/// );
2540/// ```
2541#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2542#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2543#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2544pub enum UserDefinedTypeStorage {
2545    /// No compression or out-of-line storage: `STORAGE = plain`
2546    Plain,
2547    /// Out-of-line storage allowed, no compression: `STORAGE = external`
2548    External,
2549    /// Both compression and out-of-line storage allowed: `STORAGE = extended`
2550    Extended,
2551    /// Compression allowed, out-of-line discouraged: `STORAGE = main`
2552    Main,
2553}
2554
2555impl fmt::Display for UserDefinedTypeStorage {
2556    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2557        match self {
2558            UserDefinedTypeStorage::Plain => write!(f, "plain"),
2559            UserDefinedTypeStorage::External => write!(f, "external"),
2560            UserDefinedTypeStorage::Extended => write!(f, "extended"),
2561            UserDefinedTypeStorage::Main => write!(f, "main"),
2562        }
2563    }
2564}
2565
2566/// Options for PostgreSQL `CREATE TYPE ... AS RANGE` statement.
2567///
2568/// Range types are data types representing a range of values of some element type
2569/// (called the range's subtype). These options configure the behavior of the range type.
2570///
2571/// # PostgreSQL Documentation
2572/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2573///
2574/// # Examples
2575/// ```sql
2576/// CREATE TYPE int4range AS RANGE (
2577///     SUBTYPE = int4,
2578///     SUBTYPE_OPCLASS = int4_ops,
2579///     CANONICAL = int4range_canonical,
2580///     SUBTYPE_DIFF = int4range_subdiff
2581/// );
2582/// ```
2583#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2584#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2585#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2586pub enum UserDefinedTypeRangeOption {
2587    /// The element type that the range type will represent: `SUBTYPE = subtype`
2588    Subtype(DataType),
2589    /// The operator class for the subtype: `SUBTYPE_OPCLASS = subtype_operator_class`
2590    SubtypeOpClass(ObjectName),
2591    /// Collation to use for ordering the subtype: `COLLATION = collation`
2592    Collation(ObjectName),
2593    /// Function to convert range values to canonical form: `CANONICAL = canonical_function`
2594    Canonical(ObjectName),
2595    /// Function to compute the difference between two subtype values: `SUBTYPE_DIFF = subtype_diff_function`
2596    SubtypeDiff(ObjectName),
2597    /// Name of the corresponding multirange type: `MULTIRANGE_TYPE_NAME = multirange_type_name`
2598    MultirangeTypeName(ObjectName),
2599}
2600
2601impl fmt::Display for UserDefinedTypeRangeOption {
2602    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2603        match self {
2604            UserDefinedTypeRangeOption::Subtype(dt) => write!(f, "SUBTYPE = {}", dt),
2605            UserDefinedTypeRangeOption::SubtypeOpClass(name) => {
2606                write!(f, "SUBTYPE_OPCLASS = {}", name)
2607            }
2608            UserDefinedTypeRangeOption::Collation(name) => write!(f, "COLLATION = {}", name),
2609            UserDefinedTypeRangeOption::Canonical(name) => write!(f, "CANONICAL = {}", name),
2610            UserDefinedTypeRangeOption::SubtypeDiff(name) => write!(f, "SUBTYPE_DIFF = {}", name),
2611            UserDefinedTypeRangeOption::MultirangeTypeName(name) => {
2612                write!(f, "MULTIRANGE_TYPE_NAME = {}", name)
2613            }
2614        }
2615    }
2616}
2617
2618/// Options for PostgreSQL `CREATE TYPE ... (<options>)` statement (base type definition).
2619///
2620/// Base types are the lowest-level data types in PostgreSQL. To define a new base type,
2621/// you must specify functions that convert it to and from text representation, and optionally
2622/// binary representation and other properties.
2623///
2624/// Note: This syntax uses parentheses directly after the type name, without the `AS` keyword.
2625///
2626/// # PostgreSQL Documentation
2627/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2628///
2629/// # Examples
2630/// ```sql
2631/// CREATE TYPE complex (
2632///     INPUT = complex_in,
2633///     OUTPUT = complex_out,
2634///     INTERNALLENGTH = 16,
2635///     ALIGNMENT = double
2636/// );
2637/// ```
2638#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2639#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2640#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2641pub enum UserDefinedTypeSqlDefinitionOption {
2642    /// Function to convert from external text representation to internal: `INPUT = input_function`
2643    Input(ObjectName),
2644    /// Function to convert from internal to external text representation: `OUTPUT = output_function`
2645    Output(ObjectName),
2646    /// Function to convert from external binary representation to internal: `RECEIVE = receive_function`
2647    Receive(ObjectName),
2648    /// Function to convert from internal to external binary representation: `SEND = send_function`
2649    Send(ObjectName),
2650    /// Function to convert type modifiers from text array to internal form: `TYPMOD_IN = type_modifier_input_function`
2651    TypmodIn(ObjectName),
2652    /// Function to convert type modifiers from internal to text form: `TYPMOD_OUT = type_modifier_output_function`
2653    TypmodOut(ObjectName),
2654    /// Function to compute statistics for the data type: `ANALYZE = analyze_function`
2655    Analyze(ObjectName),
2656    /// Function to handle subscripting operations: `SUBSCRIPT = subscript_function`
2657    Subscript(ObjectName),
2658    /// Internal storage size in bytes, or VARIABLE for variable-length: `INTERNALLENGTH = { internallength | VARIABLE }`
2659    InternalLength(UserDefinedTypeInternalLength),
2660    /// Indicates values are passed by value rather than by reference: `PASSEDBYVALUE`
2661    PassedByValue,
2662    /// Storage alignment requirement (1, 2, 4, or 8 bytes): `ALIGNMENT = alignment`
2663    Alignment(Alignment),
2664    /// Storage strategy for varlena types: `STORAGE = storage`
2665    Storage(UserDefinedTypeStorage),
2666    /// Copy properties from an existing type: `LIKE = like_type`
2667    Like(ObjectName),
2668    /// Type category for implicit casting rules (single char): `CATEGORY = category`
2669    Category(char),
2670    /// Whether this type is preferred within its category: `PREFERRED = preferred`
2671    Preferred(bool),
2672    /// Default value for the type: `DEFAULT = default`
2673    Default(Expr),
2674    /// Element type for array types: `ELEMENT = element`
2675    Element(DataType),
2676    /// Delimiter character for array value display: `DELIMITER = delimiter`
2677    Delimiter(String),
2678    /// Whether the type supports collation: `COLLATABLE = collatable`
2679    Collatable(bool),
2680}
2681
2682impl fmt::Display for UserDefinedTypeSqlDefinitionOption {
2683    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2684        match self {
2685            UserDefinedTypeSqlDefinitionOption::Input(name) => write!(f, "INPUT = {}", name),
2686            UserDefinedTypeSqlDefinitionOption::Output(name) => write!(f, "OUTPUT = {}", name),
2687            UserDefinedTypeSqlDefinitionOption::Receive(name) => write!(f, "RECEIVE = {}", name),
2688            UserDefinedTypeSqlDefinitionOption::Send(name) => write!(f, "SEND = {}", name),
2689            UserDefinedTypeSqlDefinitionOption::TypmodIn(name) => write!(f, "TYPMOD_IN = {}", name),
2690            UserDefinedTypeSqlDefinitionOption::TypmodOut(name) => {
2691                write!(f, "TYPMOD_OUT = {}", name)
2692            }
2693            UserDefinedTypeSqlDefinitionOption::Analyze(name) => write!(f, "ANALYZE = {}", name),
2694            UserDefinedTypeSqlDefinitionOption::Subscript(name) => {
2695                write!(f, "SUBSCRIPT = {}", name)
2696            }
2697            UserDefinedTypeSqlDefinitionOption::InternalLength(len) => {
2698                write!(f, "INTERNALLENGTH = {}", len)
2699            }
2700            UserDefinedTypeSqlDefinitionOption::PassedByValue => write!(f, "PASSEDBYVALUE"),
2701            UserDefinedTypeSqlDefinitionOption::Alignment(align) => {
2702                write!(f, "ALIGNMENT = {}", align)
2703            }
2704            UserDefinedTypeSqlDefinitionOption::Storage(storage) => {
2705                write!(f, "STORAGE = {}", storage)
2706            }
2707            UserDefinedTypeSqlDefinitionOption::Like(name) => write!(f, "LIKE = {}", name),
2708            UserDefinedTypeSqlDefinitionOption::Category(c) => write!(f, "CATEGORY = '{}'", c),
2709            UserDefinedTypeSqlDefinitionOption::Preferred(b) => write!(f, "PREFERRED = {}", b),
2710            UserDefinedTypeSqlDefinitionOption::Default(expr) => write!(f, "DEFAULT = {}", expr),
2711            UserDefinedTypeSqlDefinitionOption::Element(dt) => write!(f, "ELEMENT = {}", dt),
2712            UserDefinedTypeSqlDefinitionOption::Delimiter(s) => {
2713                write!(f, "DELIMITER = '{}'", escape_single_quote_string(s))
2714            }
2715            UserDefinedTypeSqlDefinitionOption::Collatable(b) => write!(f, "COLLATABLE = {}", b),
2716        }
2717    }
2718}
2719
2720/// PARTITION statement used in ALTER TABLE et al. such as in Hive and ClickHouse SQL.
2721/// For example, ClickHouse's OPTIMIZE TABLE supports syntax like PARTITION ID 'partition_id' and PARTITION expr.
2722/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2723#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2724#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2725#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2726pub enum Partition {
2727    /// ClickHouse supports PARTITION ID 'partition_id' syntax.
2728    Identifier(Ident),
2729    /// ClickHouse supports PARTITION expr syntax.
2730    Expr(Expr),
2731    /// ClickHouse supports PART expr which represents physical partition in disk.
2732    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
2733    Part(Expr),
2734    /// Hive supports multiple partitions in PARTITION (part1, part2, ...) syntax.
2735    Partitions(Vec<Expr>),
2736}
2737
2738impl fmt::Display for Partition {
2739    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2740        match self {
2741            Partition::Identifier(id) => write!(f, "PARTITION ID {id}"),
2742            Partition::Expr(expr) => write!(f, "PARTITION {expr}"),
2743            Partition::Part(expr) => write!(f, "PART {expr}"),
2744            Partition::Partitions(partitions) => {
2745                write!(f, "PARTITION ({})", display_comma_separated(partitions))
2746            }
2747        }
2748    }
2749}
2750
2751/// DEDUPLICATE statement used in OPTIMIZE TABLE et al. such as in ClickHouse SQL
2752/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2753#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2754#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2755#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2756pub enum Deduplicate {
2757    /// DEDUPLICATE ALL
2758    All,
2759    /// DEDUPLICATE BY expr
2760    ByExpression(Expr),
2761}
2762
2763impl fmt::Display for Deduplicate {
2764    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2765        match self {
2766            Deduplicate::All => write!(f, "DEDUPLICATE"),
2767            Deduplicate::ByExpression(expr) => write!(f, "DEDUPLICATE BY {expr}"),
2768        }
2769    }
2770}
2771
2772/// Hive supports `CLUSTERED BY` statement in `CREATE TABLE`.
2773/// Syntax: `CLUSTERED BY (col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS`
2774///
2775/// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2776#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2777#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2778#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2779pub struct ClusteredBy {
2780    /// columns used for clustering
2781    pub columns: Vec<Ident>,
2782    /// optional sorted by expressions
2783    pub sorted_by: Option<Vec<OrderByExpr>>,
2784    /// number of buckets
2785    pub num_buckets: Value,
2786}
2787
2788impl fmt::Display for ClusteredBy {
2789    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2790        write!(
2791            f,
2792            "CLUSTERED BY ({})",
2793            display_comma_separated(&self.columns)
2794        )?;
2795        if let Some(ref sorted_by) = self.sorted_by {
2796            write!(f, " SORTED BY ({})", display_comma_separated(sorted_by))?;
2797        }
2798        write!(f, " INTO {} BUCKETS", self.num_buckets)
2799    }
2800}
2801
2802/// CREATE INDEX statement.
2803#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2804#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2805#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2806pub struct CreateIndex {
2807    /// index name
2808    pub name: Option<ObjectName>,
2809    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2810    /// table name
2811    pub table_name: ObjectName,
2812    /// Index type used in the statement. Can also be found inside [`CreateIndex::index_options`]
2813    /// depending on the position of the option within the statement.
2814    pub using: Option<IndexType>,
2815    /// columns included in the index
2816    pub columns: Vec<IndexColumn>,
2817    /// whether the index is unique
2818    pub unique: bool,
2819    /// whether the index is created concurrently
2820    pub concurrently: bool,
2821    /// whether the index is created asynchronously
2822    pub r#async: bool,
2823    /// IF NOT EXISTS clause
2824    pub if_not_exists: bool,
2825    /// INCLUDE clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2826    pub include: Vec<Ident>,
2827    /// NULLS DISTINCT / NOT DISTINCT clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2828    pub nulls_distinct: Option<bool>,
2829    /// WITH clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2830    pub with: Vec<Expr>,
2831    /// WHERE clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2832    pub predicate: Option<Expr>,
2833    /// Index options: <https://www.postgresql.org/docs/current/sql-createindex.html>
2834    pub index_options: Vec<IndexOption>,
2835    /// [MySQL] allows a subset of options normally used for `ALTER TABLE`:
2836    ///
2837    /// - `ALGORITHM`
2838    /// - `LOCK`
2839    ///
2840    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/create-index.html
2841    pub alter_options: Vec<AlterTableOperation>,
2842}
2843
2844impl fmt::Display for CreateIndex {
2845    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2846        write!(
2847            f,
2848            "CREATE {unique}INDEX {concurrently}{async_}{if_not_exists}",
2849            unique = if self.unique { "UNIQUE " } else { "" },
2850            concurrently = if self.concurrently {
2851                "CONCURRENTLY "
2852            } else {
2853                ""
2854            },
2855            async_ = if self.r#async { "ASYNC " } else { "" },
2856            if_not_exists = if self.if_not_exists {
2857                "IF NOT EXISTS "
2858            } else {
2859                ""
2860            },
2861        )?;
2862        if let Some(value) = &self.name {
2863            write!(f, "{value} ")?;
2864        }
2865        write!(f, "ON {}", self.table_name)?;
2866        if let Some(value) = &self.using {
2867            write!(f, " USING {value} ")?;
2868        }
2869        write!(f, "({})", display_comma_separated(&self.columns))?;
2870        if !self.include.is_empty() {
2871            write!(f, " INCLUDE ({})", display_comma_separated(&self.include))?;
2872        }
2873        if let Some(value) = self.nulls_distinct {
2874            if value {
2875                write!(f, " NULLS DISTINCT")?;
2876            } else {
2877                write!(f, " NULLS NOT DISTINCT")?;
2878            }
2879        }
2880        if !self.with.is_empty() {
2881            write!(f, " WITH ({})", display_comma_separated(&self.with))?;
2882        }
2883        if let Some(predicate) = &self.predicate {
2884            write!(f, " WHERE {predicate}")?;
2885        }
2886        if !self.index_options.is_empty() {
2887            write!(f, " {}", display_separated(&self.index_options, " "))?;
2888        }
2889        if !self.alter_options.is_empty() {
2890            write!(f, " {}", display_separated(&self.alter_options, " "))?;
2891        }
2892        Ok(())
2893    }
2894}
2895
2896/// CREATE TABLE statement.
2897#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2898#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2899#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2900pub struct CreateTable {
2901    /// `OR REPLACE` clause
2902    pub or_replace: bool,
2903    /// `TEMP` or `TEMPORARY` clause
2904    pub temporary: bool,
2905    /// `EXTERNAL` clause
2906    pub external: bool,
2907    /// `DYNAMIC` clause
2908    pub dynamic: bool,
2909    /// `GLOBAL` clause
2910    pub global: Option<bool>,
2911    /// `IF NOT EXISTS` clause
2912    pub if_not_exists: bool,
2913    /// `TRANSIENT` clause
2914    pub transient: bool,
2915    /// `VOLATILE` clause
2916    pub volatile: bool,
2917    /// `ICEBERG` clause
2918    pub iceberg: bool,
2919    /// `SNAPSHOT` clause
2920    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_snapshot_table_statement>
2921    pub snapshot: bool,
2922    /// Table name
2923    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2924    pub name: ObjectName,
2925    /// Column definitions
2926    pub columns: Vec<ColumnDef>,
2927    /// Table constraints
2928    pub constraints: Vec<TableConstraint>,
2929    /// Hive-specific distribution style
2930    pub hive_distribution: HiveDistributionStyle,
2931    /// Hive-specific formats like `ROW FORMAT DELIMITED` or `ROW FORMAT SERDE 'serde_class' WITH SERDEPROPERTIES (...)`
2932    pub hive_formats: Option<HiveFormat>,
2933    /// Table options
2934    pub table_options: CreateTableOptions,
2935    /// General comment for the table
2936    pub file_format: Option<FileFormat>,
2937    /// Location of the table data
2938    pub location: Option<String>,
2939    /// Query used to populate the table
2940    pub query: Option<Box<Query>>,
2941    /// If the table should be created without a rowid (SQLite)
2942    pub without_rowid: bool,
2943    /// `LIKE` clause
2944    pub like: Option<CreateTableLikeKind>,
2945    /// `CLONE` clause
2946    pub clone: Option<ObjectName>,
2947    /// Table version (for systems that support versioned tables)
2948    pub version: Option<TableVersion>,
2949    /// For Hive dialect, the table comment is after the column definitions without `=`,
2950    /// so the `comment` field is optional and different than the comment field in the general options list.
2951    /// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2952    pub comment: Option<CommentDef>,
2953    /// ClickHouse "ON COMMIT" clause:
2954    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
2955    pub on_commit: Option<OnCommit>,
2956    /// ClickHouse "ON CLUSTER" clause:
2957    /// <https://clickhouse.com/docs/en/sql-reference/distributed-ddl/>
2958    pub on_cluster: Option<Ident>,
2959    /// ClickHouse "PRIMARY KEY " clause.
2960    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
2961    pub primary_key: Option<Box<Expr>>,
2962    /// ClickHouse "ORDER BY " clause. Note that omitted ORDER BY is different
2963    /// than empty (represented as ()), the latter meaning "no sorting".
2964    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
2965    pub order_by: Option<OneOrManyWithParens<Expr>>,
2966    /// BigQuery: A partition expression for the table.
2967    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#partition_expression>
2968    pub partition_by: Option<Box<Expr>>,
2969    /// BigQuery: Table clustering column list.
2970    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#table_option_list>
2971    /// Snowflake: Table clustering list which contains base column, expressions on base columns.
2972    /// <https://docs.snowflake.com/en/user-guide/tables-clustering-keys#defining-a-clustering-key-for-a-table>
2973    pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
2974    /// Hive: Table clustering column list.
2975    /// <https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable>
2976    pub clustered_by: Option<ClusteredBy>,
2977    /// Postgres `INHERITs` clause, which contains the list of tables from which
2978    /// the new table inherits.
2979    /// <https://www.postgresql.org/docs/current/ddl-inherit.html>
2980    /// <https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-INHERITS>
2981    pub inherits: Option<Vec<ObjectName>>,
2982    /// PostgreSQL `PARTITION OF` clause to create a partition of a parent table.
2983    /// Contains the parent table name.
2984    /// <https://www.postgresql.org/docs/current/sql-createtable.html>
2985    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2986    pub partition_of: Option<ObjectName>,
2987    /// PostgreSQL partition bound specification for PARTITION OF.
2988    /// <https://www.postgresql.org/docs/current/sql-createtable.html>
2989    pub for_values: Option<ForValues>,
2990    /// SQLite "STRICT" clause.
2991    /// if the "STRICT" table-option keyword is added to the end, after the closing ")",
2992    /// then strict typing rules apply to that table.
2993    pub strict: bool,
2994    /// Snowflake "COPY GRANTS" clause
2995    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2996    pub copy_grants: bool,
2997    /// Snowflake "ENABLE_SCHEMA_EVOLUTION" clause
2998    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2999    pub enable_schema_evolution: Option<bool>,
3000    /// Snowflake "CHANGE_TRACKING" clause
3001    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3002    pub change_tracking: Option<bool>,
3003    /// Snowflake "DATA_RETENTION_TIME_IN_DAYS" clause
3004    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3005    pub data_retention_time_in_days: Option<u64>,
3006    /// Snowflake "MAX_DATA_EXTENSION_TIME_IN_DAYS" clause
3007    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3008    pub max_data_extension_time_in_days: Option<u64>,
3009    /// Snowflake "DEFAULT_DDL_COLLATION" clause
3010    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3011    pub default_ddl_collation: Option<String>,
3012    /// Snowflake "WITH AGGREGATION POLICY" clause
3013    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3014    pub with_aggregation_policy: Option<ObjectName>,
3015    /// Snowflake "WITH ROW ACCESS POLICY" clause
3016    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3017    pub with_row_access_policy: Option<RowAccessPolicy>,
3018    /// Snowflake `WITH STORAGE LIFECYCLE POLICY` clause
3019    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3020    pub with_storage_lifecycle_policy: Option<StorageLifecyclePolicy>,
3021    /// Snowflake "WITH TAG" clause
3022    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3023    pub with_tags: Option<Vec<Tag>>,
3024    /// Snowflake "EXTERNAL_VOLUME" clause for Iceberg tables
3025    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3026    pub external_volume: Option<String>,
3027    /// Snowflake "BASE_LOCATION" clause for Iceberg tables
3028    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3029    pub base_location: Option<String>,
3030    /// Snowflake "CATALOG" clause for Iceberg tables
3031    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3032    pub catalog: Option<String>,
3033    /// Snowflake "CATALOG_SYNC" clause for Iceberg tables
3034    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3035    pub catalog_sync: Option<String>,
3036    /// Snowflake "STORAGE_SERIALIZATION_POLICY" clause for Iceberg tables
3037    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3038    pub storage_serialization_policy: Option<StorageSerializationPolicy>,
3039    /// Snowflake "TARGET_LAG" clause for dybamic tables
3040    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3041    pub target_lag: Option<String>,
3042    /// Snowflake "WAREHOUSE" clause for dybamic tables
3043    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3044    pub warehouse: Option<Ident>,
3045    /// Snowflake "REFRESH_MODE" clause for dybamic tables
3046    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3047    pub refresh_mode: Option<RefreshModeKind>,
3048    /// Snowflake "INITIALIZE" clause for dybamic tables
3049    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3050    pub initialize: Option<InitializeKind>,
3051    /// Snowflake "REQUIRE USER" clause for dybamic tables
3052    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3053    pub require_user: bool,
3054    /// Redshift `DISTSTYLE` option
3055    /// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3056    pub diststyle: Option<DistStyle>,
3057    /// Redshift `DISTKEY` option
3058    /// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3059    pub distkey: Option<Expr>,
3060    /// Redshift `SORTKEY` option
3061    /// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3062    pub sortkey: Option<Vec<Expr>>,
3063    /// Redshift `BACKUP` option: `BACKUP { YES | NO }`
3064    /// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3065    pub backup: Option<bool>,
3066}
3067
3068impl fmt::Display for CreateTable {
3069    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3070        // We want to allow the following options
3071        // Empty column list, allowed by PostgreSQL:
3072        //   `CREATE TABLE t ()`
3073        // No columns provided for CREATE TABLE AS:
3074        //   `CREATE TABLE t AS SELECT a from t2`
3075        // Columns provided for CREATE TABLE AS:
3076        //   `CREATE TABLE t (a INT) AS SELECT a from t2`
3077        write!(
3078            f,
3079            "CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}{dynamic}{iceberg}{snapshot}TABLE {if_not_exists}{name}",
3080            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
3081            external = if self.external { "EXTERNAL " } else { "" },
3082            snapshot = if self.snapshot { "SNAPSHOT " } else { "" },
3083            global = self.global
3084                .map(|global| {
3085                    if global {
3086                        "GLOBAL "
3087                    } else {
3088                        "LOCAL "
3089                    }
3090                })
3091                .unwrap_or(""),
3092            if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
3093            temporary = if self.temporary { "TEMPORARY " } else { "" },
3094            transient = if self.transient { "TRANSIENT " } else { "" },
3095            volatile = if self.volatile { "VOLATILE " } else { "" },
3096            // Only for Snowflake
3097            iceberg = if self.iceberg { "ICEBERG " } else { "" },
3098            dynamic = if self.dynamic { "DYNAMIC " } else { "" },
3099            name = self.name,
3100        )?;
3101        if let Some(partition_of) = &self.partition_of {
3102            write!(f, " PARTITION OF {partition_of}")?;
3103        }
3104        if let Some(on_cluster) = &self.on_cluster {
3105            write!(f, " ON CLUSTER {on_cluster}")?;
3106        }
3107        if !self.columns.is_empty() || !self.constraints.is_empty() {
3108            f.write_str(" (")?;
3109            NewLine.fmt(f)?;
3110            Indent(DisplayCommaSeparated(&self.columns)).fmt(f)?;
3111            if !self.columns.is_empty() && !self.constraints.is_empty() {
3112                f.write_str(",")?;
3113                SpaceOrNewline.fmt(f)?;
3114            }
3115            Indent(DisplayCommaSeparated(&self.constraints)).fmt(f)?;
3116            NewLine.fmt(f)?;
3117            f.write_str(")")?;
3118        } else if self.query.is_none()
3119            && self.like.is_none()
3120            && self.clone.is_none()
3121            && self.partition_of.is_none()
3122        {
3123            // PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
3124            f.write_str(" ()")?;
3125        } else if let Some(CreateTableLikeKind::Parenthesized(like_in_columns_list)) = &self.like {
3126            write!(f, " ({like_in_columns_list})")?;
3127        }
3128        if let Some(for_values) = &self.for_values {
3129            write!(f, " {for_values}")?;
3130        }
3131
3132        // Hive table comment should be after column definitions, please refer to:
3133        // [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
3134        if let Some(comment) = &self.comment {
3135            write!(f, " COMMENT '{comment}'")?;
3136        }
3137
3138        // Only for SQLite
3139        if self.without_rowid {
3140            write!(f, " WITHOUT ROWID")?;
3141        }
3142
3143        if let Some(CreateTableLikeKind::Plain(like)) = &self.like {
3144            write!(f, " {like}")?;
3145        }
3146
3147        if let Some(c) = &self.clone {
3148            write!(f, " CLONE {c}")?;
3149        }
3150
3151        if let Some(version) = &self.version {
3152            write!(f, " {version}")?;
3153        }
3154
3155        match &self.hive_distribution {
3156            HiveDistributionStyle::PARTITIONED { columns } => {
3157                write!(f, " PARTITIONED BY ({})", display_comma_separated(columns))?;
3158            }
3159            HiveDistributionStyle::SKEWED {
3160                columns,
3161                on,
3162                stored_as_directories,
3163            } => {
3164                write!(
3165                    f,
3166                    " SKEWED BY ({})) ON ({})",
3167                    display_comma_separated(columns),
3168                    display_comma_separated(on)
3169                )?;
3170                if *stored_as_directories {
3171                    write!(f, " STORED AS DIRECTORIES")?;
3172                }
3173            }
3174            _ => (),
3175        }
3176
3177        if let Some(clustered_by) = &self.clustered_by {
3178            write!(f, " {clustered_by}")?;
3179        }
3180
3181        if let Some(HiveFormat {
3182            row_format,
3183            serde_properties,
3184            storage,
3185            location,
3186        }) = &self.hive_formats
3187        {
3188            match row_format {
3189                Some(HiveRowFormat::SERDE { class }) => write!(f, " ROW FORMAT SERDE '{class}'")?,
3190                Some(HiveRowFormat::DELIMITED { delimiters }) => {
3191                    write!(f, " ROW FORMAT DELIMITED")?;
3192                    if !delimiters.is_empty() {
3193                        write!(f, " {}", display_separated(delimiters, " "))?;
3194                    }
3195                }
3196                None => (),
3197            }
3198            match storage {
3199                Some(HiveIOFormat::IOF {
3200                    input_format,
3201                    output_format,
3202                }) => write!(
3203                    f,
3204                    " STORED AS INPUTFORMAT {input_format} OUTPUTFORMAT {output_format}"
3205                )?,
3206                Some(HiveIOFormat::FileFormat { format }) if !self.external => {
3207                    write!(f, " STORED AS {format}")?
3208                }
3209                _ => (),
3210            }
3211            if let Some(serde_properties) = serde_properties.as_ref() {
3212                write!(
3213                    f,
3214                    " WITH SERDEPROPERTIES ({})",
3215                    display_comma_separated(serde_properties)
3216                )?;
3217            }
3218            if !self.external {
3219                if let Some(loc) = location {
3220                    write!(f, " LOCATION '{loc}'")?;
3221                }
3222            }
3223        }
3224        if self.external {
3225            if let Some(file_format) = self.file_format {
3226                write!(f, " STORED AS {file_format}")?;
3227            }
3228            if let Some(location) = &self.location {
3229                write!(f, " LOCATION '{location}'")?;
3230            }
3231        }
3232
3233        match &self.table_options {
3234            options @ CreateTableOptions::With(_)
3235            | options @ CreateTableOptions::Plain(_)
3236            | options @ CreateTableOptions::TableProperties(_) => write!(f, " {options}")?,
3237            _ => (),
3238        }
3239
3240        if let Some(primary_key) = &self.primary_key {
3241            write!(f, " PRIMARY KEY {primary_key}")?;
3242        }
3243        if let Some(order_by) = &self.order_by {
3244            write!(f, " ORDER BY {order_by}")?;
3245        }
3246        if let Some(inherits) = &self.inherits {
3247            write!(f, " INHERITS ({})", display_comma_separated(inherits))?;
3248        }
3249        if let Some(partition_by) = self.partition_by.as_ref() {
3250            write!(f, " PARTITION BY {partition_by}")?;
3251        }
3252        if let Some(cluster_by) = self.cluster_by.as_ref() {
3253            write!(f, " CLUSTER BY {cluster_by}")?;
3254        }
3255        if let options @ CreateTableOptions::Options(_) = &self.table_options {
3256            write!(f, " {options}")?;
3257        }
3258        if let Some(external_volume) = self.external_volume.as_ref() {
3259            write!(f, " EXTERNAL_VOLUME='{external_volume}'")?;
3260        }
3261
3262        if let Some(catalog) = self.catalog.as_ref() {
3263            write!(f, " CATALOG='{catalog}'")?;
3264        }
3265
3266        if self.iceberg {
3267            if let Some(base_location) = self.base_location.as_ref() {
3268                write!(f, " BASE_LOCATION='{base_location}'")?;
3269            }
3270        }
3271
3272        if let Some(catalog_sync) = self.catalog_sync.as_ref() {
3273            write!(f, " CATALOG_SYNC='{catalog_sync}'")?;
3274        }
3275
3276        if let Some(storage_serialization_policy) = self.storage_serialization_policy.as_ref() {
3277            write!(
3278                f,
3279                " STORAGE_SERIALIZATION_POLICY={storage_serialization_policy}"
3280            )?;
3281        }
3282
3283        if self.copy_grants {
3284            write!(f, " COPY GRANTS")?;
3285        }
3286
3287        if let Some(is_enabled) = self.enable_schema_evolution {
3288            write!(
3289                f,
3290                " ENABLE_SCHEMA_EVOLUTION={}",
3291                if is_enabled { "TRUE" } else { "FALSE" }
3292            )?;
3293        }
3294
3295        if let Some(is_enabled) = self.change_tracking {
3296            write!(
3297                f,
3298                " CHANGE_TRACKING={}",
3299                if is_enabled { "TRUE" } else { "FALSE" }
3300            )?;
3301        }
3302
3303        if let Some(data_retention_time_in_days) = self.data_retention_time_in_days {
3304            write!(
3305                f,
3306                " DATA_RETENTION_TIME_IN_DAYS={data_retention_time_in_days}",
3307            )?;
3308        }
3309
3310        if let Some(max_data_extension_time_in_days) = self.max_data_extension_time_in_days {
3311            write!(
3312                f,
3313                " MAX_DATA_EXTENSION_TIME_IN_DAYS={max_data_extension_time_in_days}",
3314            )?;
3315        }
3316
3317        if let Some(default_ddl_collation) = &self.default_ddl_collation {
3318            write!(f, " DEFAULT_DDL_COLLATION='{default_ddl_collation}'",)?;
3319        }
3320
3321        if let Some(with_aggregation_policy) = &self.with_aggregation_policy {
3322            write!(f, " WITH AGGREGATION POLICY {with_aggregation_policy}",)?;
3323        }
3324
3325        if let Some(row_access_policy) = &self.with_row_access_policy {
3326            write!(f, " {row_access_policy}",)?;
3327        }
3328
3329        if let Some(storage_lifecycle_policy) = &self.with_storage_lifecycle_policy {
3330            write!(f, " {storage_lifecycle_policy}",)?;
3331        }
3332
3333        if let Some(tag) = &self.with_tags {
3334            write!(f, " WITH TAG ({})", display_comma_separated(tag.as_slice()))?;
3335        }
3336
3337        if let Some(target_lag) = &self.target_lag {
3338            write!(f, " TARGET_LAG='{target_lag}'")?;
3339        }
3340
3341        if let Some(warehouse) = &self.warehouse {
3342            write!(f, " WAREHOUSE={warehouse}")?;
3343        }
3344
3345        if let Some(refresh_mode) = &self.refresh_mode {
3346            write!(f, " REFRESH_MODE={refresh_mode}")?;
3347        }
3348
3349        if let Some(initialize) = &self.initialize {
3350            write!(f, " INITIALIZE={initialize}")?;
3351        }
3352
3353        if self.require_user {
3354            write!(f, " REQUIRE USER")?;
3355        }
3356
3357        if self.on_commit.is_some() {
3358            let on_commit = match self.on_commit {
3359                Some(OnCommit::DeleteRows) => "ON COMMIT DELETE ROWS",
3360                Some(OnCommit::PreserveRows) => "ON COMMIT PRESERVE ROWS",
3361                Some(OnCommit::Drop) => "ON COMMIT DROP",
3362                None => "",
3363            };
3364            write!(f, " {on_commit}")?;
3365        }
3366        if self.strict {
3367            write!(f, " STRICT")?;
3368        }
3369        if let Some(backup) = self.backup {
3370            write!(f, " BACKUP {}", if backup { "YES" } else { "NO" })?;
3371        }
3372        if let Some(diststyle) = &self.diststyle {
3373            write!(f, " DISTSTYLE {diststyle}")?;
3374        }
3375        if let Some(distkey) = &self.distkey {
3376            write!(f, " DISTKEY({distkey})")?;
3377        }
3378        if let Some(sortkey) = &self.sortkey {
3379            write!(f, " SORTKEY({})", display_comma_separated(sortkey))?;
3380        }
3381        if let Some(query) = &self.query {
3382            write!(f, " AS {query}")?;
3383        }
3384        Ok(())
3385    }
3386}
3387
3388/// PostgreSQL partition bound specification for `PARTITION OF`.
3389///
3390/// Specifies partition bounds for a child partition table.
3391///
3392/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createtable.html)
3393#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3394#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3395#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3396pub enum ForValues {
3397    /// `FOR VALUES IN (expr, ...)`
3398    In(Vec<Expr>),
3399    /// `FOR VALUES FROM (expr|MINVALUE|MAXVALUE, ...) TO (expr|MINVALUE|MAXVALUE, ...)`
3400    From {
3401        /// The lower bound values for the partition.
3402        from: Vec<PartitionBoundValue>,
3403        /// The upper bound values for the partition.
3404        to: Vec<PartitionBoundValue>,
3405    },
3406    /// `FOR VALUES WITH (MODULUS n, REMAINDER r)`
3407    With {
3408        /// The modulus value for hash partitioning.
3409        modulus: u64,
3410        /// The remainder value for hash partitioning.
3411        remainder: u64,
3412    },
3413    /// `DEFAULT`
3414    Default,
3415}
3416
3417impl fmt::Display for ForValues {
3418    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3419        match self {
3420            ForValues::In(values) => {
3421                write!(f, "FOR VALUES IN ({})", display_comma_separated(values))
3422            }
3423            ForValues::From { from, to } => {
3424                write!(
3425                    f,
3426                    "FOR VALUES FROM ({}) TO ({})",
3427                    display_comma_separated(from),
3428                    display_comma_separated(to)
3429                )
3430            }
3431            ForValues::With { modulus, remainder } => {
3432                write!(
3433                    f,
3434                    "FOR VALUES WITH (MODULUS {modulus}, REMAINDER {remainder})"
3435                )
3436            }
3437            ForValues::Default => write!(f, "DEFAULT"),
3438        }
3439    }
3440}
3441
3442/// A value in a partition bound specification.
3443///
3444/// Used in RANGE partition bounds where values can be expressions,
3445/// MINVALUE (negative infinity), or MAXVALUE (positive infinity).
3446#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3447#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3448#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3449pub enum PartitionBoundValue {
3450    /// An expression representing a partition bound value.
3451    Expr(Expr),
3452    /// Represents negative infinity in partition bounds.
3453    MinValue,
3454    /// Represents positive infinity in partition bounds.
3455    MaxValue,
3456}
3457
3458impl fmt::Display for PartitionBoundValue {
3459    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3460        match self {
3461            PartitionBoundValue::Expr(expr) => write!(f, "{expr}"),
3462            PartitionBoundValue::MinValue => write!(f, "MINVALUE"),
3463            PartitionBoundValue::MaxValue => write!(f, "MAXVALUE"),
3464        }
3465    }
3466}
3467
3468/// Redshift distribution style for `CREATE TABLE`.
3469///
3470/// See [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html)
3471#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3472#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3473#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3474pub enum DistStyle {
3475    /// `DISTSTYLE AUTO`
3476    Auto,
3477    /// `DISTSTYLE EVEN`
3478    Even,
3479    /// `DISTSTYLE KEY`
3480    Key,
3481    /// `DISTSTYLE ALL`
3482    All,
3483}
3484
3485impl fmt::Display for DistStyle {
3486    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3487        match self {
3488            DistStyle::Auto => write!(f, "AUTO"),
3489            DistStyle::Even => write!(f, "EVEN"),
3490            DistStyle::Key => write!(f, "KEY"),
3491            DistStyle::All => write!(f, "ALL"),
3492        }
3493    }
3494}
3495
3496#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3497#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3498#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3499/// ```sql
3500/// CREATE DOMAIN name [ AS ] data_type
3501///         [ COLLATE collation ]
3502///         [ DEFAULT expression ]
3503///         [ domain_constraint [ ... ] ]
3504///
3505///     where domain_constraint is:
3506///
3507///     [ CONSTRAINT constraint_name ]
3508///     { NOT NULL | NULL | CHECK (expression) }
3509/// ```
3510/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createdomain.html)
3511pub struct CreateDomain {
3512    /// The name of the domain to be created.
3513    pub name: ObjectName,
3514    /// The data type of the domain.
3515    pub data_type: DataType,
3516    /// The collation of the domain.
3517    pub collation: Option<Ident>,
3518    /// The default value of the domain.
3519    pub default: Option<Expr>,
3520    /// The constraints of the domain.
3521    pub constraints: Vec<TableConstraint>,
3522}
3523
3524impl fmt::Display for CreateDomain {
3525    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3526        write!(
3527            f,
3528            "CREATE DOMAIN {name} AS {data_type}",
3529            name = self.name,
3530            data_type = self.data_type
3531        )?;
3532        if let Some(collation) = &self.collation {
3533            write!(f, " COLLATE {collation}")?;
3534        }
3535        if let Some(default) = &self.default {
3536            write!(f, " DEFAULT {default}")?;
3537        }
3538        if !self.constraints.is_empty() {
3539            write!(f, " {}", display_separated(&self.constraints, " "))?;
3540        }
3541        Ok(())
3542    }
3543}
3544
3545/// The return type of a `CREATE FUNCTION` statement.
3546#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3547#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3548#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3549pub enum FunctionReturnType {
3550    /// `RETURNS <type>`
3551    DataType(DataType),
3552    /// `RETURNS SETOF <type>`
3553    ///
3554    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3555    SetOf(DataType),
3556}
3557
3558impl fmt::Display for FunctionReturnType {
3559    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3560        match self {
3561            FunctionReturnType::DataType(data_type) => write!(f, "{data_type}"),
3562            FunctionReturnType::SetOf(data_type) => write!(f, "SETOF {data_type}"),
3563        }
3564    }
3565}
3566
3567#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3568#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3569#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3570/// CREATE FUNCTION statement
3571pub struct CreateFunction {
3572    /// True if this is a `CREATE OR ALTER FUNCTION` statement
3573    ///
3574    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql?view=sql-server-ver16#or-alter)
3575    pub or_alter: bool,
3576    /// True if this is a `CREATE OR REPLACE FUNCTION` statement
3577    pub or_replace: bool,
3578    /// True if this is a `CREATE TEMPORARY FUNCTION` statement
3579    pub temporary: bool,
3580    /// True if this is a `CREATE IF NOT EXISTS FUNCTION` statement
3581    pub if_not_exists: bool,
3582    /// Name of the function to be created.
3583    pub name: ObjectName,
3584    /// List of arguments for the function.
3585    pub args: Option<Vec<OperateFunctionArg>>,
3586    /// The return type of the function.
3587    pub return_type: Option<FunctionReturnType>,
3588    /// The expression that defines the function.
3589    ///
3590    /// Examples:
3591    /// ```sql
3592    /// AS ((SELECT 1))
3593    /// AS "console.log();"
3594    /// ```
3595    pub function_body: Option<CreateFunctionBody>,
3596    /// Behavior attribute for the function
3597    ///
3598    /// IMMUTABLE | STABLE | VOLATILE
3599    ///
3600    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3601    pub behavior: Option<FunctionBehavior>,
3602    /// CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
3603    ///
3604    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3605    pub called_on_null: Option<FunctionCalledOnNull>,
3606    /// PARALLEL { UNSAFE | RESTRICTED | SAFE }
3607    ///
3608    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3609    pub parallel: Option<FunctionParallel>,
3610    /// SECURITY { DEFINER | INVOKER }
3611    ///
3612    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3613    pub security: Option<FunctionSecurity>,
3614    /// SET configuration_parameter clauses
3615    ///
3616    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3617    pub set_params: Vec<FunctionDefinitionSetParam>,
3618    /// USING ... (Hive only)
3619    pub using: Option<CreateFunctionUsing>,
3620    /// Language used in a UDF definition.
3621    ///
3622    /// Example:
3623    /// ```sql
3624    /// CREATE FUNCTION foo() LANGUAGE js AS "console.log();"
3625    /// ```
3626    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_javascript_udf)
3627    pub language: Option<Ident>,
3628    /// Determinism keyword used for non-sql UDF definitions.
3629    ///
3630    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
3631    pub determinism_specifier: Option<FunctionDeterminismSpecifier>,
3632    /// List of options for creating the function.
3633    ///
3634    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
3635    pub options: Option<Vec<SqlOption>>,
3636    /// Connection resource for a remote function.
3637    ///
3638    /// Example:
3639    /// ```sql
3640    /// CREATE FUNCTION foo()
3641    /// RETURNS FLOAT64
3642    /// REMOTE WITH CONNECTION us.myconnection
3643    /// ```
3644    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
3645    pub remote_connection: Option<ObjectName>,
3646}
3647
3648impl fmt::Display for CreateFunction {
3649    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3650        write!(
3651            f,
3652            "CREATE {or_alter}{or_replace}{temp}FUNCTION {if_not_exists}{name}",
3653            name = self.name,
3654            temp = if self.temporary { "TEMPORARY " } else { "" },
3655            or_alter = if self.or_alter { "OR ALTER " } else { "" },
3656            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
3657            if_not_exists = if self.if_not_exists {
3658                "IF NOT EXISTS "
3659            } else {
3660                ""
3661            },
3662        )?;
3663        if let Some(args) = &self.args {
3664            write!(f, "({})", display_comma_separated(args))?;
3665        }
3666        if let Some(return_type) = &self.return_type {
3667            write!(f, " RETURNS {return_type}")?;
3668        }
3669        if let Some(determinism_specifier) = &self.determinism_specifier {
3670            write!(f, " {determinism_specifier}")?;
3671        }
3672        if let Some(language) = &self.language {
3673            write!(f, " LANGUAGE {language}")?;
3674        }
3675        if let Some(behavior) = &self.behavior {
3676            write!(f, " {behavior}")?;
3677        }
3678        if let Some(called_on_null) = &self.called_on_null {
3679            write!(f, " {called_on_null}")?;
3680        }
3681        if let Some(parallel) = &self.parallel {
3682            write!(f, " {parallel}")?;
3683        }
3684        if let Some(security) = &self.security {
3685            write!(f, " {security}")?;
3686        }
3687        for set_param in &self.set_params {
3688            write!(f, " {set_param}")?;
3689        }
3690        if let Some(remote_connection) = &self.remote_connection {
3691            write!(f, " REMOTE WITH CONNECTION {remote_connection}")?;
3692        }
3693        if let Some(CreateFunctionBody::AsBeforeOptions { body, link_symbol }) = &self.function_body
3694        {
3695            write!(f, " AS {body}")?;
3696            if let Some(link_symbol) = link_symbol {
3697                write!(f, ", {link_symbol}")?;
3698            }
3699        }
3700        if let Some(CreateFunctionBody::Return(function_body)) = &self.function_body {
3701            write!(f, " RETURN {function_body}")?;
3702        }
3703        if let Some(CreateFunctionBody::AsReturnExpr(function_body)) = &self.function_body {
3704            write!(f, " AS RETURN {function_body}")?;
3705        }
3706        if let Some(CreateFunctionBody::AsReturnSelect(function_body)) = &self.function_body {
3707            write!(f, " AS RETURN {function_body}")?;
3708        }
3709        if let Some(using) = &self.using {
3710            write!(f, " {using}")?;
3711        }
3712        if let Some(options) = &self.options {
3713            write!(
3714                f,
3715                " OPTIONS({})",
3716                display_comma_separated(options.as_slice())
3717            )?;
3718        }
3719        if let Some(CreateFunctionBody::AsAfterOptions(function_body)) = &self.function_body {
3720            write!(f, " AS {function_body}")?;
3721        }
3722        if let Some(CreateFunctionBody::AsBeginEnd(bes)) = &self.function_body {
3723            write!(f, " AS {bes}")?;
3724        }
3725        Ok(())
3726    }
3727}
3728
3729/// ```sql
3730/// CREATE CONNECTOR [IF NOT EXISTS] connector_name
3731/// [TYPE datasource_type]
3732/// [URL datasource_url]
3733/// [COMMENT connector_comment]
3734/// [WITH DCPROPERTIES(property_name=property_value, ...)]
3735/// ```
3736///
3737/// [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
3738#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3739#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3740#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3741pub struct CreateConnector {
3742    /// The name of the connector to be created.
3743    pub name: Ident,
3744    /// Whether `IF NOT EXISTS` was specified.
3745    pub if_not_exists: bool,
3746    /// The type of the connector.
3747    pub connector_type: Option<String>,
3748    /// The URL of the connector.
3749    pub url: Option<String>,
3750    /// The comment for the connector.
3751    pub comment: Option<CommentDef>,
3752    /// The DC properties for the connector.
3753    pub with_dcproperties: Option<Vec<SqlOption>>,
3754}
3755
3756impl fmt::Display for CreateConnector {
3757    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3758        write!(
3759            f,
3760            "CREATE CONNECTOR {if_not_exists}{name}",
3761            if_not_exists = if self.if_not_exists {
3762                "IF NOT EXISTS "
3763            } else {
3764                ""
3765            },
3766            name = self.name,
3767        )?;
3768
3769        if let Some(connector_type) = &self.connector_type {
3770            write!(f, " TYPE '{connector_type}'")?;
3771        }
3772
3773        if let Some(url) = &self.url {
3774            write!(f, " URL '{url}'")?;
3775        }
3776
3777        if let Some(comment) = &self.comment {
3778            write!(f, " COMMENT = '{comment}'")?;
3779        }
3780
3781        if let Some(with_dcproperties) = &self.with_dcproperties {
3782            write!(
3783                f,
3784                " WITH DCPROPERTIES({})",
3785                display_comma_separated(with_dcproperties)
3786            )?;
3787        }
3788
3789        Ok(())
3790    }
3791}
3792
3793/// An `ALTER SCHEMA` (`Statement::AlterSchema`) operation.
3794///
3795/// See [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#alter_schema_collate_statement)
3796/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterschema.html)
3797#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3798#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3799#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3800pub enum AlterSchemaOperation {
3801    /// Set the default collation for the schema.
3802    SetDefaultCollate {
3803        /// The collation to set as default.
3804        collate: Expr,
3805    },
3806    /// Add a replica to the schema.
3807    AddReplica {
3808        /// The replica to add.
3809        replica: Ident,
3810        /// Optional options for the replica.
3811        options: Option<Vec<SqlOption>>,
3812    },
3813    /// Drop a replica from the schema.
3814    DropReplica {
3815        /// The replica to drop.
3816        replica: Ident,
3817    },
3818    /// Set options for the schema.
3819    SetOptionsParens {
3820        /// The options to set.
3821        options: Vec<SqlOption>,
3822    },
3823    /// Rename the schema.
3824    Rename {
3825        /// The new name for the schema.
3826        name: ObjectName,
3827    },
3828    /// Change the owner of the schema.
3829    OwnerTo {
3830        /// The new owner of the schema.
3831        owner: Owner,
3832    },
3833}
3834
3835impl fmt::Display for AlterSchemaOperation {
3836    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3837        match self {
3838            AlterSchemaOperation::SetDefaultCollate { collate } => {
3839                write!(f, "SET DEFAULT COLLATE {collate}")
3840            }
3841            AlterSchemaOperation::AddReplica { replica, options } => {
3842                write!(f, "ADD REPLICA {replica}")?;
3843                if let Some(options) = options {
3844                    write!(f, " OPTIONS ({})", display_comma_separated(options))?;
3845                }
3846                Ok(())
3847            }
3848            AlterSchemaOperation::DropReplica { replica } => write!(f, "DROP REPLICA {replica}"),
3849            AlterSchemaOperation::SetOptionsParens { options } => {
3850                write!(f, "SET OPTIONS ({})", display_comma_separated(options))
3851            }
3852            AlterSchemaOperation::Rename { name } => write!(f, "RENAME TO {name}"),
3853            AlterSchemaOperation::OwnerTo { owner } => write!(f, "OWNER TO {owner}"),
3854        }
3855    }
3856}
3857/// `RenameTableNameKind` is the kind used in an `ALTER TABLE _ RENAME` statement.
3858///
3859/// Note: [MySQL] is the only database that supports the AS keyword for this operation.
3860///
3861/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
3862#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3863#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3864#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3865pub enum RenameTableNameKind {
3866    /// `AS new_table_name`
3867    As(ObjectName),
3868    /// `TO new_table_name`
3869    To(ObjectName),
3870}
3871
3872impl fmt::Display for RenameTableNameKind {
3873    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3874        match self {
3875            RenameTableNameKind::As(name) => write!(f, "AS {name}"),
3876            RenameTableNameKind::To(name) => write!(f, "TO {name}"),
3877        }
3878    }
3879}
3880
3881#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3882#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3883#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3884/// An `ALTER SCHEMA` (`Statement::AlterSchema`) statement.
3885pub struct AlterSchema {
3886    /// The schema name to alter.
3887    pub name: ObjectName,
3888    /// Whether `IF EXISTS` was specified.
3889    pub if_exists: bool,
3890    /// The list of operations to perform on the schema.
3891    pub operations: Vec<AlterSchemaOperation>,
3892}
3893
3894impl fmt::Display for AlterSchema {
3895    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3896        write!(f, "ALTER SCHEMA ")?;
3897        if self.if_exists {
3898            write!(f, "IF EXISTS ")?;
3899        }
3900        write!(f, "{}", self.name)?;
3901        for operation in &self.operations {
3902            write!(f, " {operation}")?;
3903        }
3904
3905        Ok(())
3906    }
3907}
3908
3909impl Spanned for RenameTableNameKind {
3910    fn span(&self) -> Span {
3911        match self {
3912            RenameTableNameKind::As(name) => name.span(),
3913            RenameTableNameKind::To(name) => name.span(),
3914        }
3915    }
3916}
3917
3918#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
3919#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3920#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3921/// Whether the syntax used for the trigger object (ROW or STATEMENT) is `FOR` or `FOR EACH`.
3922pub enum TriggerObjectKind {
3923    /// The `FOR` syntax is used.
3924    For(TriggerObject),
3925    /// The `FOR EACH` syntax is used.
3926    ForEach(TriggerObject),
3927}
3928
3929impl Display for TriggerObjectKind {
3930    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3931        match self {
3932            TriggerObjectKind::For(obj) => write!(f, "FOR {obj}"),
3933            TriggerObjectKind::ForEach(obj) => write!(f, "FOR EACH {obj}"),
3934        }
3935    }
3936}
3937
3938#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3939#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3940#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3941/// CREATE TRIGGER
3942///
3943/// Examples:
3944///
3945/// ```sql
3946/// CREATE TRIGGER trigger_name
3947/// BEFORE INSERT ON table_name
3948/// FOR EACH ROW
3949/// EXECUTE FUNCTION trigger_function();
3950/// ```
3951///
3952/// Postgres: <https://www.postgresql.org/docs/current/sql-createtrigger.html>
3953/// SQL Server: <https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql>
3954pub struct CreateTrigger {
3955    /// True if this is a `CREATE OR ALTER TRIGGER` statement
3956    ///
3957    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql?view=sql-server-ver16#arguments)
3958    pub or_alter: bool,
3959    /// True if this is a temporary trigger.
3960    ///
3961    /// Examples:
3962    ///
3963    /// ```sql
3964    /// CREATE TEMP TRIGGER trigger_name
3965    /// ```
3966    ///
3967    /// or
3968    ///
3969    /// ```sql
3970    /// CREATE TEMPORARY TRIGGER trigger_name;
3971    /// CREATE TEMP TRIGGER trigger_name;
3972    /// ```
3973    ///
3974    /// [SQLite](https://sqlite.org/lang_createtrigger.html#temp_triggers_on_non_temp_tables)
3975    pub temporary: bool,
3976    /// The `OR REPLACE` clause is used to re-create the trigger if it already exists.
3977    ///
3978    /// Example:
3979    /// ```sql
3980    /// CREATE OR REPLACE TRIGGER trigger_name
3981    /// AFTER INSERT ON table_name
3982    /// FOR EACH ROW
3983    /// EXECUTE FUNCTION trigger_function();
3984    /// ```
3985    pub or_replace: bool,
3986    /// The `CONSTRAINT` keyword is used to create a trigger as a constraint.
3987    pub is_constraint: bool,
3988    /// The name of the trigger to be created.
3989    pub name: ObjectName,
3990    /// Determines whether the function is called before, after, or instead of the event.
3991    ///
3992    /// Example of BEFORE:
3993    ///
3994    /// ```sql
3995    /// CREATE TRIGGER trigger_name
3996    /// BEFORE INSERT ON table_name
3997    /// FOR EACH ROW
3998    /// EXECUTE FUNCTION trigger_function();
3999    /// ```
4000    ///
4001    /// Example of AFTER:
4002    ///
4003    /// ```sql
4004    /// CREATE TRIGGER trigger_name
4005    /// AFTER INSERT ON table_name
4006    /// FOR EACH ROW
4007    /// EXECUTE FUNCTION trigger_function();
4008    /// ```
4009    ///
4010    /// Example of INSTEAD OF:
4011    ///
4012    /// ```sql
4013    /// CREATE TRIGGER trigger_name
4014    /// INSTEAD OF INSERT ON table_name
4015    /// FOR EACH ROW
4016    /// EXECUTE FUNCTION trigger_function();
4017    /// ```
4018    pub period: Option<TriggerPeriod>,
4019    /// Whether the trigger period was specified before the target table name.
4020    /// This does not refer to whether the period is BEFORE, AFTER, or INSTEAD OF,
4021    /// but rather the position of the period clause in relation to the table name.
4022    ///
4023    /// ```sql
4024    /// -- period_before_table == true: Postgres, MySQL, and standard SQL
4025    /// CREATE TRIGGER t BEFORE INSERT ON table_name ...;
4026    /// -- period_before_table == false: MSSQL
4027    /// CREATE TRIGGER t ON table_name BEFORE INSERT ...;
4028    /// ```
4029    pub period_before_table: bool,
4030    /// Multiple events can be specified using OR, such as `INSERT`, `UPDATE`, `DELETE`, or `TRUNCATE`.
4031    pub events: Vec<TriggerEvent>,
4032    /// The table on which the trigger is to be created.
4033    pub table_name: ObjectName,
4034    /// The optional referenced table name that can be referenced via
4035    /// the `FROM` keyword.
4036    pub referenced_table_name: Option<ObjectName>,
4037    /// This keyword immediately precedes the declaration of one or two relation names that provide access to the transition relations of the triggering statement.
4038    pub referencing: Vec<TriggerReferencing>,
4039    /// This specifies whether the trigger function should be fired once for
4040    /// every row affected by the trigger event, or just once per SQL statement.
4041    /// This is optional in some SQL dialects, such as SQLite, and if not specified, in
4042    /// those cases, the implied default is `FOR EACH ROW`.
4043    pub trigger_object: Option<TriggerObjectKind>,
4044    ///  Triggering conditions
4045    pub condition: Option<Expr>,
4046    /// Execute logic block
4047    pub exec_body: Option<TriggerExecBody>,
4048    /// For MSSQL and dialects where statements are preceded by `AS`
4049    pub statements_as: bool,
4050    /// For SQL dialects with statement(s) for a body
4051    pub statements: Option<ConditionalStatements>,
4052    /// The characteristic of the trigger, which include whether the trigger is `DEFERRABLE`, `INITIALLY DEFERRED`, or `INITIALLY IMMEDIATE`,
4053    pub characteristics: Option<ConstraintCharacteristics>,
4054}
4055
4056impl Display for CreateTrigger {
4057    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4058        let CreateTrigger {
4059            or_alter,
4060            temporary,
4061            or_replace,
4062            is_constraint,
4063            name,
4064            period_before_table,
4065            period,
4066            events,
4067            table_name,
4068            referenced_table_name,
4069            referencing,
4070            trigger_object,
4071            condition,
4072            exec_body,
4073            statements_as,
4074            statements,
4075            characteristics,
4076        } = self;
4077        write!(
4078            f,
4079            "CREATE {temporary}{or_alter}{or_replace}{is_constraint}TRIGGER {name} ",
4080            temporary = if *temporary { "TEMPORARY " } else { "" },
4081            or_alter = if *or_alter { "OR ALTER " } else { "" },
4082            or_replace = if *or_replace { "OR REPLACE " } else { "" },
4083            is_constraint = if *is_constraint { "CONSTRAINT " } else { "" },
4084        )?;
4085
4086        if *period_before_table {
4087            if let Some(p) = period {
4088                write!(f, "{p} ")?;
4089            }
4090            if !events.is_empty() {
4091                write!(f, "{} ", display_separated(events, " OR "))?;
4092            }
4093            write!(f, "ON {table_name}")?;
4094        } else {
4095            write!(f, "ON {table_name} ")?;
4096            if let Some(p) = period {
4097                write!(f, "{p}")?;
4098            }
4099            if !events.is_empty() {
4100                write!(f, " {}", display_separated(events, ", "))?;
4101            }
4102        }
4103
4104        if let Some(referenced_table_name) = referenced_table_name {
4105            write!(f, " FROM {referenced_table_name}")?;
4106        }
4107
4108        if let Some(characteristics) = characteristics {
4109            write!(f, " {characteristics}")?;
4110        }
4111
4112        if !referencing.is_empty() {
4113            write!(f, " REFERENCING {}", display_separated(referencing, " "))?;
4114        }
4115
4116        if let Some(trigger_object) = trigger_object {
4117            write!(f, " {trigger_object}")?;
4118        }
4119        if let Some(condition) = condition {
4120            write!(f, " WHEN {condition}")?;
4121        }
4122        if let Some(exec_body) = exec_body {
4123            write!(f, " EXECUTE {exec_body}")?;
4124        }
4125        if let Some(statements) = statements {
4126            if *statements_as {
4127                write!(f, " AS")?;
4128            }
4129            write!(f, " {statements}")?;
4130        }
4131        Ok(())
4132    }
4133}
4134
4135#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4136#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4137#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4138/// DROP TRIGGER
4139///
4140/// ```sql
4141/// DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
4142/// ```
4143///
4144pub struct DropTrigger {
4145    /// Whether to include the `IF EXISTS` clause.
4146    pub if_exists: bool,
4147    /// The name of the trigger to be dropped.
4148    pub trigger_name: ObjectName,
4149    /// The name of the table from which the trigger is to be dropped.
4150    pub table_name: Option<ObjectName>,
4151    /// `CASCADE` or `RESTRICT`
4152    pub option: Option<ReferentialAction>,
4153}
4154
4155impl fmt::Display for DropTrigger {
4156    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4157        let DropTrigger {
4158            if_exists,
4159            trigger_name,
4160            table_name,
4161            option,
4162        } = self;
4163        write!(f, "DROP TRIGGER")?;
4164        if *if_exists {
4165            write!(f, " IF EXISTS")?;
4166        }
4167        match &table_name {
4168            Some(table_name) => write!(f, " {trigger_name} ON {table_name}")?,
4169            None => write!(f, " {trigger_name}")?,
4170        };
4171        if let Some(option) = option {
4172            write!(f, " {option}")?;
4173        }
4174        Ok(())
4175    }
4176}
4177
4178/// A `TRUNCATE` statement.
4179///
4180/// ```sql
4181/// TRUNCATE TABLE [IF EXISTS] table_names [PARTITION (partitions)] [RESTART IDENTITY | CONTINUE IDENTITY] [CASCADE | RESTRICT] [ON CLUSTER cluster_name]
4182/// ```
4183#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4184#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4185#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4186pub struct Truncate {
4187    /// Table names to truncate
4188    pub table_names: Vec<super::TruncateTableTarget>,
4189    /// Optional partition specification
4190    pub partitions: Option<Vec<Expr>>,
4191    /// TABLE - optional keyword
4192    pub table: bool,
4193    /// Snowflake/Redshift-specific option: [ IF EXISTS ]
4194    pub if_exists: bool,
4195    /// Postgres-specific option: [ RESTART IDENTITY | CONTINUE IDENTITY ]
4196    pub identity: Option<super::TruncateIdentityOption>,
4197    /// Postgres-specific option: [ CASCADE | RESTRICT ]
4198    pub cascade: Option<super::CascadeOption>,
4199    /// ClickHouse-specific option: [ ON CLUSTER cluster_name ]
4200    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/truncate/)
4201    pub on_cluster: Option<Ident>,
4202}
4203
4204impl fmt::Display for Truncate {
4205    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4206        let table = if self.table { "TABLE " } else { "" };
4207        let if_exists = if self.if_exists { "IF EXISTS " } else { "" };
4208
4209        write!(
4210            f,
4211            "TRUNCATE {table}{if_exists}{table_names}",
4212            table_names = display_comma_separated(&self.table_names)
4213        )?;
4214
4215        if let Some(identity) = &self.identity {
4216            match identity {
4217                super::TruncateIdentityOption::Restart => write!(f, " RESTART IDENTITY")?,
4218                super::TruncateIdentityOption::Continue => write!(f, " CONTINUE IDENTITY")?,
4219            }
4220        }
4221        if let Some(cascade) = &self.cascade {
4222            match cascade {
4223                super::CascadeOption::Cascade => write!(f, " CASCADE")?,
4224                super::CascadeOption::Restrict => write!(f, " RESTRICT")?,
4225            }
4226        }
4227
4228        if let Some(ref parts) = &self.partitions {
4229            if !parts.is_empty() {
4230                write!(f, " PARTITION ({})", display_comma_separated(parts))?;
4231            }
4232        }
4233        if let Some(on_cluster) = &self.on_cluster {
4234            write!(f, " ON CLUSTER {on_cluster}")?;
4235        }
4236        Ok(())
4237    }
4238}
4239
4240impl Spanned for Truncate {
4241    fn span(&self) -> Span {
4242        Span::union_iter(
4243            self.table_names.iter().map(|i| i.name.span()).chain(
4244                self.partitions
4245                    .iter()
4246                    .flat_map(|i| i.iter().map(|k| k.span())),
4247            ),
4248        )
4249    }
4250}
4251
4252/// An `MSCK` statement.
4253///
4254/// ```sql
4255/// MSCK [REPAIR] TABLE table_name [ADD|DROP|SYNC PARTITIONS]
4256/// ```
4257/// MSCK (Hive) - MetaStore Check command
4258#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4259#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4260#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4261pub struct Msck {
4262    /// Table name to check
4263    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
4264    pub table_name: ObjectName,
4265    /// Whether to repair the table
4266    pub repair: bool,
4267    /// Partition action (ADD, DROP, or SYNC)
4268    pub partition_action: Option<super::AddDropSync>,
4269}
4270
4271impl fmt::Display for Msck {
4272    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4273        write!(
4274            f,
4275            "MSCK {repair}TABLE {table}",
4276            repair = if self.repair { "REPAIR " } else { "" },
4277            table = self.table_name
4278        )?;
4279        if let Some(pa) = &self.partition_action {
4280            write!(f, " {pa}")?;
4281        }
4282        Ok(())
4283    }
4284}
4285
4286impl Spanned for Msck {
4287    fn span(&self) -> Span {
4288        self.table_name.span()
4289    }
4290}
4291
4292/// CREATE VIEW statement.
4293#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4294#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4295#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4296pub struct CreateView {
4297    /// True if this is a `CREATE OR ALTER VIEW` statement
4298    ///
4299    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-view-transact-sql)
4300    pub or_alter: bool,
4301    /// The `OR REPLACE` clause is used to re-create the view if it already exists.
4302    pub or_replace: bool,
4303    /// if true, has MATERIALIZED view modifier
4304    pub materialized: bool,
4305    /// Snowflake: SECURE view modifier
4306    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
4307    pub secure: bool,
4308    /// View name
4309    pub name: ObjectName,
4310    /// If `if_not_exists` is true, this flag is set to true if the view name comes before the `IF NOT EXISTS` clause.
4311    /// Example:
4312    /// ```sql
4313    /// CREATE VIEW myview IF NOT EXISTS AS SELECT 1`
4314    ///  ```
4315    /// Otherwise, the flag is set to false if the view name comes after the clause
4316    /// Example:
4317    /// ```sql
4318    /// CREATE VIEW IF NOT EXISTS myview AS SELECT 1`
4319    ///  ```
4320    pub name_before_not_exists: bool,
4321    /// Optional column definitions
4322    pub columns: Vec<ViewColumnDef>,
4323    /// The query that defines the view.
4324    pub query: Box<Query>,
4325    /// Table options (e.g., WITH (..), OPTIONS (...))
4326    pub options: CreateTableOptions,
4327    /// BigQuery: CLUSTER BY columns
4328    pub cluster_by: Vec<Ident>,
4329    /// Snowflake: Views can have comments in Snowflake.
4330    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
4331    pub comment: Option<String>,
4332    /// if true, has RedShift [`WITH NO SCHEMA BINDING`] clause <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_VIEW.html>
4333    pub with_no_schema_binding: bool,
4334    /// if true, has SQLite `IF NOT EXISTS` clause <https://www.sqlite.org/lang_createview.html>
4335    pub if_not_exists: bool,
4336    /// if true, has SQLite `TEMP` or `TEMPORARY` clause <https://www.sqlite.org/lang_createview.html>
4337    pub temporary: bool,
4338    /// Snowflake: `COPY GRANTS` clause
4339    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view>
4340    pub copy_grants: bool,
4341    /// if not None, has Clickhouse `TO` clause, specify the table into which to insert results
4342    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/view#materialized-view>
4343    pub to: Option<ObjectName>,
4344    /// MySQL: Optional parameters for the view algorithm, definer, and security context
4345    pub params: Option<CreateViewParams>,
4346}
4347
4348impl fmt::Display for CreateView {
4349    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4350        write!(
4351            f,
4352            "CREATE {or_alter}{or_replace}",
4353            or_alter = if self.or_alter { "OR ALTER " } else { "" },
4354            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
4355        )?;
4356        if let Some(ref params) = self.params {
4357            params.fmt(f)?;
4358        }
4359        write!(
4360            f,
4361            "{secure}{materialized}{temporary}VIEW {if_not_and_name}{to}",
4362            if_not_and_name = if self.if_not_exists {
4363                if self.name_before_not_exists {
4364                    format!("{} IF NOT EXISTS", self.name)
4365                } else {
4366                    format!("IF NOT EXISTS {}", self.name)
4367                }
4368            } else {
4369                format!("{}", self.name)
4370            },
4371            secure = if self.secure { "SECURE " } else { "" },
4372            materialized = if self.materialized {
4373                "MATERIALIZED "
4374            } else {
4375                ""
4376            },
4377            temporary = if self.temporary { "TEMPORARY " } else { "" },
4378            to = self
4379                .to
4380                .as_ref()
4381                .map(|to| format!(" TO {to}"))
4382                .unwrap_or_default()
4383        )?;
4384        if self.copy_grants {
4385            write!(f, " COPY GRANTS")?;
4386        }
4387        if !self.columns.is_empty() {
4388            write!(f, " ({})", display_comma_separated(&self.columns))?;
4389        }
4390        if matches!(self.options, CreateTableOptions::With(_)) {
4391            write!(f, " {}", self.options)?;
4392        }
4393        if let Some(ref comment) = self.comment {
4394            write!(f, " COMMENT = '{}'", escape_single_quote_string(comment))?;
4395        }
4396        if !self.cluster_by.is_empty() {
4397            write!(
4398                f,
4399                " CLUSTER BY ({})",
4400                display_comma_separated(&self.cluster_by)
4401            )?;
4402        }
4403        if matches!(self.options, CreateTableOptions::Options(_)) {
4404            write!(f, " {}", self.options)?;
4405        }
4406        f.write_str(" AS")?;
4407        SpaceOrNewline.fmt(f)?;
4408        self.query.fmt(f)?;
4409        if self.with_no_schema_binding {
4410            write!(f, " WITH NO SCHEMA BINDING")?;
4411        }
4412        Ok(())
4413    }
4414}
4415
4416/// CREATE EXTENSION statement
4417/// Note: this is a PostgreSQL-specific statement
4418#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4419#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4420#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4421pub struct CreateExtension {
4422    /// Extension name
4423    pub name: Ident,
4424    /// Whether `IF NOT EXISTS` was specified for the CREATE EXTENSION.
4425    pub if_not_exists: bool,
4426    /// Whether `CASCADE` was specified for the CREATE EXTENSION.
4427    pub cascade: bool,
4428    /// Optional schema name for the extension.
4429    pub schema: Option<Ident>,
4430    /// Optional version for the extension.
4431    pub version: Option<Ident>,
4432}
4433
4434impl fmt::Display for CreateExtension {
4435    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4436        write!(
4437            f,
4438            "CREATE EXTENSION {if_not_exists}{name}",
4439            if_not_exists = if self.if_not_exists {
4440                "IF NOT EXISTS "
4441            } else {
4442                ""
4443            },
4444            name = self.name
4445        )?;
4446        if self.cascade || self.schema.is_some() || self.version.is_some() {
4447            write!(f, " WITH")?;
4448
4449            if let Some(name) = &self.schema {
4450                write!(f, " SCHEMA {name}")?;
4451            }
4452            if let Some(version) = &self.version {
4453                write!(f, " VERSION {version}")?;
4454            }
4455            if self.cascade {
4456                write!(f, " CASCADE")?;
4457            }
4458        }
4459
4460        Ok(())
4461    }
4462}
4463
4464impl Spanned for CreateExtension {
4465    fn span(&self) -> Span {
4466        Span::empty()
4467    }
4468}
4469
4470/// DROP EXTENSION statement
4471/// Note: this is a PostgreSQL-specific statement
4472///
4473/// # References
4474///
4475/// PostgreSQL Documentation:
4476/// <https://www.postgresql.org/docs/current/sql-dropextension.html>
4477#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4478#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4479#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4480pub struct DropExtension {
4481    /// One or more extension names to drop
4482    pub names: Vec<Ident>,
4483    /// Whether `IF EXISTS` was specified for the DROP EXTENSION.
4484    pub if_exists: bool,
4485    /// `CASCADE` or `RESTRICT` behaviour for the drop.
4486    pub cascade_or_restrict: Option<ReferentialAction>,
4487}
4488
4489impl fmt::Display for DropExtension {
4490    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4491        write!(f, "DROP EXTENSION")?;
4492        if self.if_exists {
4493            write!(f, " IF EXISTS")?;
4494        }
4495        write!(f, " {}", display_comma_separated(&self.names))?;
4496        if let Some(cascade_or_restrict) = &self.cascade_or_restrict {
4497            write!(f, " {cascade_or_restrict}")?;
4498        }
4499        Ok(())
4500    }
4501}
4502
4503impl Spanned for DropExtension {
4504    fn span(&self) -> Span {
4505        Span::empty()
4506    }
4507}
4508
4509/// CREATE COLLATION statement.
4510/// Note: this is a PostgreSQL-specific statement.
4511#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4512#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4513#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4514pub struct CreateCollation {
4515    /// Whether `IF NOT EXISTS` was specified.
4516    pub if_not_exists: bool,
4517    /// Name of the collation being created.
4518    pub name: ObjectName,
4519    /// Source definition for the collation.
4520    pub definition: CreateCollationDefinition,
4521}
4522
4523/// Definition forms supported by `CREATE COLLATION`.
4524#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4525#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4526#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4527pub enum CreateCollationDefinition {
4528    /// Create from an existing collation.
4529    ///
4530    /// ```sql
4531    /// CREATE COLLATION name FROM existing_collation
4532    /// ```
4533    From(ObjectName),
4534    /// Create with an option list.
4535    ///
4536    /// ```sql
4537    /// CREATE COLLATION name (key = value, ...)
4538    /// ```
4539    Options(Vec<SqlOption>),
4540}
4541
4542impl fmt::Display for CreateCollation {
4543    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4544        write!(
4545            f,
4546            "CREATE COLLATION {if_not_exists}{name}",
4547            if_not_exists = if self.if_not_exists {
4548                "IF NOT EXISTS "
4549            } else {
4550                ""
4551            },
4552            name = self.name
4553        )?;
4554        match &self.definition {
4555            CreateCollationDefinition::From(existing_collation) => {
4556                write!(f, " FROM {existing_collation}")
4557            }
4558            CreateCollationDefinition::Options(options) => {
4559                write!(f, " ({})", display_comma_separated(options))
4560            }
4561        }
4562    }
4563}
4564
4565impl Spanned for CreateCollation {
4566    fn span(&self) -> Span {
4567        Span::empty()
4568    }
4569}
4570
4571/// ALTER COLLATION statement.
4572/// Note: this is a PostgreSQL-specific statement.
4573#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4574#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4575#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4576pub struct AlterCollation {
4577    /// Name of the collation being altered.
4578    pub name: ObjectName,
4579    /// The operation to perform on the collation.
4580    pub operation: AlterCollationOperation,
4581}
4582
4583/// Operations supported by `ALTER COLLATION`.
4584#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4585#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4586#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4587pub enum AlterCollationOperation {
4588    /// Rename the collation.
4589    ///
4590    /// ```sql
4591    /// ALTER COLLATION name RENAME TO new_name
4592    /// ```
4593    RenameTo {
4594        /// New collation name.
4595        new_name: Ident,
4596    },
4597    /// Change the collation owner.
4598    ///
4599    /// ```sql
4600    /// ALTER COLLATION name OWNER TO role_name
4601    /// ```
4602    OwnerTo(Owner),
4603    /// Move the collation to another schema.
4604    ///
4605    /// ```sql
4606    /// ALTER COLLATION name SET SCHEMA new_schema
4607    /// ```
4608    SetSchema {
4609        /// Target schema name.
4610        schema_name: ObjectName,
4611    },
4612    /// Refresh collation version metadata.
4613    ///
4614    /// ```sql
4615    /// ALTER COLLATION name REFRESH VERSION
4616    /// ```
4617    RefreshVersion,
4618}
4619
4620impl fmt::Display for AlterCollationOperation {
4621    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4622        match self {
4623            AlterCollationOperation::RenameTo { new_name } => write!(f, "RENAME TO {new_name}"),
4624            AlterCollationOperation::OwnerTo(owner) => write!(f, "OWNER TO {owner}"),
4625            AlterCollationOperation::SetSchema { schema_name } => {
4626                write!(f, "SET SCHEMA {schema_name}")
4627            }
4628            AlterCollationOperation::RefreshVersion => write!(f, "REFRESH VERSION"),
4629        }
4630    }
4631}
4632
4633impl fmt::Display for AlterCollation {
4634    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4635        write!(f, "ALTER COLLATION {} {}", self.name, self.operation)
4636    }
4637}
4638
4639impl Spanned for AlterCollation {
4640    fn span(&self) -> Span {
4641        Span::empty()
4642    }
4643}
4644
4645/// Table type for ALTER TABLE statements.
4646/// Used to distinguish between regular tables, Iceberg tables, and Dynamic tables.
4647#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4648#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4649#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4650pub enum AlterTableType {
4651    /// Iceberg table type
4652    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
4653    Iceberg,
4654    /// Dynamic table type
4655    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-dynamic-table>
4656    Dynamic,
4657    /// External table type
4658    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
4659    External,
4660}
4661
4662/// ALTER TABLE statement
4663#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4664#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4665#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4666pub struct AlterTable {
4667    /// Table name
4668    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
4669    pub name: ObjectName,
4670    /// Whether `IF EXISTS` was specified for the `ALTER TABLE`.
4671    pub if_exists: bool,
4672    /// Whether the `ONLY` keyword was used (restrict scope to the named table).
4673    pub only: bool,
4674    /// List of `ALTER TABLE` operations to apply.
4675    pub operations: Vec<AlterTableOperation>,
4676    /// Optional Hive `SET LOCATION` clause for the alter operation.
4677    pub location: Option<HiveSetLocation>,
4678    /// ClickHouse dialect supports `ON CLUSTER` clause for ALTER TABLE
4679    /// For example: `ALTER TABLE table_name ON CLUSTER cluster_name ADD COLUMN c UInt32`
4680    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/update)
4681    pub on_cluster: Option<Ident>,
4682    /// Table type: None for regular tables, Some(AlterTableType) for Iceberg or Dynamic tables
4683    pub table_type: Option<AlterTableType>,
4684    /// Token that represents the end of the statement (semicolon or EOF)
4685    pub end_token: AttachedToken,
4686}
4687
4688impl fmt::Display for AlterTable {
4689    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4690        match &self.table_type {
4691            Some(AlterTableType::Iceberg) => write!(f, "ALTER ICEBERG TABLE ")?,
4692            Some(AlterTableType::Dynamic) => write!(f, "ALTER DYNAMIC TABLE ")?,
4693            Some(AlterTableType::External) => write!(f, "ALTER EXTERNAL TABLE ")?,
4694            None => write!(f, "ALTER TABLE ")?,
4695        }
4696
4697        if self.if_exists {
4698            write!(f, "IF EXISTS ")?;
4699        }
4700        if self.only {
4701            write!(f, "ONLY ")?;
4702        }
4703        write!(f, "{} ", &self.name)?;
4704        if let Some(cluster) = &self.on_cluster {
4705            write!(f, "ON CLUSTER {cluster} ")?;
4706        }
4707        write!(f, "{}", display_comma_separated(&self.operations))?;
4708        if let Some(loc) = &self.location {
4709            write!(f, " {loc}")?
4710        }
4711        Ok(())
4712    }
4713}
4714
4715/// DROP FUNCTION statement
4716#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4717#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4718#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4719pub struct DropFunction {
4720    /// Whether to include the `IF EXISTS` clause.
4721    pub if_exists: bool,
4722    /// One or more functions to drop
4723    pub func_desc: Vec<FunctionDesc>,
4724    /// `CASCADE` or `RESTRICT`
4725    pub drop_behavior: Option<DropBehavior>,
4726}
4727
4728impl fmt::Display for DropFunction {
4729    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4730        write!(
4731            f,
4732            "DROP FUNCTION{} {}",
4733            if self.if_exists { " IF EXISTS" } else { "" },
4734            display_comma_separated(&self.func_desc),
4735        )?;
4736        if let Some(op) = &self.drop_behavior {
4737            write!(f, " {op}")?;
4738        }
4739        Ok(())
4740    }
4741}
4742
4743impl Spanned for DropFunction {
4744    fn span(&self) -> Span {
4745        Span::empty()
4746    }
4747}
4748
4749/// CREATE OPERATOR statement
4750/// See <https://www.postgresql.org/docs/current/sql-createoperator.html>
4751#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4752#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4753#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4754pub struct CreateOperator {
4755    /// Operator name (can be schema-qualified)
4756    pub name: ObjectName,
4757    /// FUNCTION or PROCEDURE parameter (function name)
4758    pub function: ObjectName,
4759    /// Whether PROCEDURE keyword was used (vs FUNCTION)
4760    pub is_procedure: bool,
4761    /// LEFTARG parameter (left operand type)
4762    pub left_arg: Option<DataType>,
4763    /// RIGHTARG parameter (right operand type)
4764    pub right_arg: Option<DataType>,
4765    /// Operator options (COMMUTATOR, NEGATOR, RESTRICT, JOIN, HASHES, MERGES)
4766    pub options: Vec<OperatorOption>,
4767}
4768
4769/// CREATE OPERATOR FAMILY statement
4770/// See <https://www.postgresql.org/docs/current/sql-createopfamily.html>
4771#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4772#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4773#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4774pub struct CreateOperatorFamily {
4775    /// Operator family name (can be schema-qualified)
4776    pub name: ObjectName,
4777    /// Index method (btree, hash, gist, gin, etc.)
4778    pub using: Ident,
4779}
4780
4781/// CREATE OPERATOR CLASS statement
4782/// See <https://www.postgresql.org/docs/current/sql-createopclass.html>
4783#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4784#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4785#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4786pub struct CreateOperatorClass {
4787    /// Operator class name (can be schema-qualified)
4788    pub name: ObjectName,
4789    /// Whether this is the default operator class for the type
4790    pub default: bool,
4791    /// The data type
4792    pub for_type: DataType,
4793    /// Index method (btree, hash, gist, gin, etc.)
4794    pub using: Ident,
4795    /// Optional operator family name
4796    pub family: Option<ObjectName>,
4797    /// List of operator class items (operators, functions, storage)
4798    pub items: Vec<OperatorClassItem>,
4799}
4800
4801impl fmt::Display for CreateOperator {
4802    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4803        write!(f, "CREATE OPERATOR {} (", self.name)?;
4804
4805        let function_keyword = if self.is_procedure {
4806            "PROCEDURE"
4807        } else {
4808            "FUNCTION"
4809        };
4810        let mut params = vec![format!("{} = {}", function_keyword, self.function)];
4811
4812        if let Some(left_arg) = &self.left_arg {
4813            params.push(format!("LEFTARG = {}", left_arg));
4814        }
4815        if let Some(right_arg) = &self.right_arg {
4816            params.push(format!("RIGHTARG = {}", right_arg));
4817        }
4818
4819        for option in &self.options {
4820            params.push(option.to_string());
4821        }
4822
4823        write!(f, "{}", params.join(", "))?;
4824        write!(f, ")")
4825    }
4826}
4827
4828impl fmt::Display for CreateOperatorFamily {
4829    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4830        write!(
4831            f,
4832            "CREATE OPERATOR FAMILY {} USING {}",
4833            self.name, self.using
4834        )
4835    }
4836}
4837
4838impl fmt::Display for CreateOperatorClass {
4839    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4840        write!(f, "CREATE OPERATOR CLASS {}", self.name)?;
4841        if self.default {
4842            write!(f, " DEFAULT")?;
4843        }
4844        write!(f, " FOR TYPE {} USING {}", self.for_type, self.using)?;
4845        if let Some(family) = &self.family {
4846            write!(f, " FAMILY {}", family)?;
4847        }
4848        write!(f, " AS {}", display_comma_separated(&self.items))
4849    }
4850}
4851
4852/// Operator argument types for CREATE OPERATOR CLASS
4853#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4854#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4855#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4856pub struct OperatorArgTypes {
4857    /// Left-hand operand data type for the operator.
4858    pub left: DataType,
4859    /// Right-hand operand data type for the operator.
4860    pub right: DataType,
4861}
4862
4863impl fmt::Display for OperatorArgTypes {
4864    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4865        write!(f, "{}, {}", self.left, self.right)
4866    }
4867}
4868
4869/// An item in a CREATE OPERATOR CLASS statement
4870#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4871#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4872#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4873pub enum OperatorClassItem {
4874    /// `OPERATOR` clause describing a specific operator implementation.
4875    Operator {
4876        /// Strategy number identifying the operator position in the opclass.
4877        strategy_number: u64,
4878        /// The operator name referenced by this clause.
4879        operator_name: ObjectName,
4880        /// Optional operator argument types.
4881        op_types: Option<OperatorArgTypes>,
4882        /// Optional purpose such as `FOR SEARCH` or `FOR ORDER BY`.
4883        purpose: Option<OperatorPurpose>,
4884    },
4885    /// `FUNCTION` clause describing a support function for the operator class.
4886    Function {
4887        /// Support function number for this entry.
4888        support_number: u64,
4889        /// Optional function argument types for the operator class.
4890        op_types: Option<Vec<DataType>>,
4891        /// The function name implementing the support function.
4892        function_name: ObjectName,
4893        /// Function argument types for the support function.
4894        argument_types: Vec<DataType>,
4895    },
4896    /// `STORAGE` clause specifying the storage type.
4897    Storage {
4898        /// The storage data type.
4899        storage_type: DataType,
4900    },
4901}
4902
4903/// Purpose of an operator in an operator class
4904#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4905#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4906#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4907pub enum OperatorPurpose {
4908    /// Purpose: used for index/search operations.
4909    ForSearch,
4910    /// Purpose: used for ORDER BY; optionally includes a sort family name.
4911    ForOrderBy {
4912        /// Optional sort family object name.
4913        sort_family: ObjectName,
4914    },
4915}
4916
4917impl fmt::Display for OperatorClassItem {
4918    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4919        match self {
4920            OperatorClassItem::Operator {
4921                strategy_number,
4922                operator_name,
4923                op_types,
4924                purpose,
4925            } => {
4926                write!(f, "OPERATOR {strategy_number} {operator_name}")?;
4927                if let Some(types) = op_types {
4928                    write!(f, " ({types})")?;
4929                }
4930                if let Some(purpose) = purpose {
4931                    write!(f, " {purpose}")?;
4932                }
4933                Ok(())
4934            }
4935            OperatorClassItem::Function {
4936                support_number,
4937                op_types,
4938                function_name,
4939                argument_types,
4940            } => {
4941                write!(f, "FUNCTION {support_number}")?;
4942                if let Some(types) = op_types {
4943                    write!(f, " ({})", display_comma_separated(types))?;
4944                }
4945                write!(f, " {function_name}")?;
4946                if !argument_types.is_empty() {
4947                    write!(f, "({})", display_comma_separated(argument_types))?;
4948                }
4949                Ok(())
4950            }
4951            OperatorClassItem::Storage { storage_type } => {
4952                write!(f, "STORAGE {storage_type}")
4953            }
4954        }
4955    }
4956}
4957
4958impl fmt::Display for OperatorPurpose {
4959    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4960        match self {
4961            OperatorPurpose::ForSearch => write!(f, "FOR SEARCH"),
4962            OperatorPurpose::ForOrderBy { sort_family } => {
4963                write!(f, "FOR ORDER BY {sort_family}")
4964            }
4965        }
4966    }
4967}
4968
4969/// `DROP OPERATOR` statement
4970/// See <https://www.postgresql.org/docs/current/sql-dropoperator.html>
4971#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4972#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4973#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4974pub struct DropOperator {
4975    /// `IF EXISTS` clause
4976    pub if_exists: bool,
4977    /// One or more operators to drop with their signatures
4978    pub operators: Vec<DropOperatorSignature>,
4979    /// `CASCADE or RESTRICT`
4980    pub drop_behavior: Option<DropBehavior>,
4981}
4982
4983/// Operator signature for a `DROP OPERATOR` statement
4984#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4985#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4986#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4987pub struct DropOperatorSignature {
4988    /// Operator name
4989    pub name: ObjectName,
4990    /// Left operand type
4991    pub left_type: Option<DataType>,
4992    /// Right operand type
4993    pub right_type: DataType,
4994}
4995
4996impl fmt::Display for DropOperatorSignature {
4997    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4998        write!(f, "{} (", self.name)?;
4999        if let Some(left_type) = &self.left_type {
5000            write!(f, "{}", left_type)?;
5001        } else {
5002            write!(f, "NONE")?;
5003        }
5004        write!(f, ", {})", self.right_type)
5005    }
5006}
5007
5008impl fmt::Display for DropOperator {
5009    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5010        write!(f, "DROP OPERATOR")?;
5011        if self.if_exists {
5012            write!(f, " IF EXISTS")?;
5013        }
5014        write!(f, " {}", display_comma_separated(&self.operators))?;
5015        if let Some(drop_behavior) = &self.drop_behavior {
5016            write!(f, " {}", drop_behavior)?;
5017        }
5018        Ok(())
5019    }
5020}
5021
5022impl Spanned for DropOperator {
5023    fn span(&self) -> Span {
5024        Span::empty()
5025    }
5026}
5027
5028/// `DROP OPERATOR FAMILY` statement
5029/// See <https://www.postgresql.org/docs/current/sql-dropopfamily.html>
5030#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5031#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5032#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5033pub struct DropOperatorFamily {
5034    /// `IF EXISTS` clause
5035    pub if_exists: bool,
5036    /// One or more operator families to drop
5037    pub names: Vec<ObjectName>,
5038    /// Index method (btree, hash, gist, gin, etc.)
5039    pub using: Ident,
5040    /// `CASCADE or RESTRICT`
5041    pub drop_behavior: Option<DropBehavior>,
5042}
5043
5044impl fmt::Display for DropOperatorFamily {
5045    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5046        write!(f, "DROP OPERATOR FAMILY")?;
5047        if self.if_exists {
5048            write!(f, " IF EXISTS")?;
5049        }
5050        write!(f, " {}", display_comma_separated(&self.names))?;
5051        write!(f, " USING {}", self.using)?;
5052        if let Some(drop_behavior) = &self.drop_behavior {
5053            write!(f, " {}", drop_behavior)?;
5054        }
5055        Ok(())
5056    }
5057}
5058
5059impl Spanned for DropOperatorFamily {
5060    fn span(&self) -> Span {
5061        Span::empty()
5062    }
5063}
5064
5065/// `DROP OPERATOR CLASS` statement
5066/// See <https://www.postgresql.org/docs/current/sql-dropopclass.html>
5067#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5068#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5069#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5070pub struct DropOperatorClass {
5071    /// `IF EXISTS` clause
5072    pub if_exists: bool,
5073    /// One or more operator classes to drop
5074    pub names: Vec<ObjectName>,
5075    /// Index method (btree, hash, gist, gin, etc.)
5076    pub using: Ident,
5077    /// `CASCADE or RESTRICT`
5078    pub drop_behavior: Option<DropBehavior>,
5079}
5080
5081impl fmt::Display for DropOperatorClass {
5082    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5083        write!(f, "DROP OPERATOR CLASS")?;
5084        if self.if_exists {
5085            write!(f, " IF EXISTS")?;
5086        }
5087        write!(f, " {}", display_comma_separated(&self.names))?;
5088        write!(f, " USING {}", self.using)?;
5089        if let Some(drop_behavior) = &self.drop_behavior {
5090            write!(f, " {}", drop_behavior)?;
5091        }
5092        Ok(())
5093    }
5094}
5095
5096impl Spanned for DropOperatorClass {
5097    fn span(&self) -> Span {
5098        Span::empty()
5099    }
5100}
5101
5102/// An item in an ALTER OPERATOR FAMILY ADD statement
5103#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5104#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5105#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5106pub enum OperatorFamilyItem {
5107    /// `OPERATOR` clause in an operator family modification.
5108    Operator {
5109        /// Strategy number for the operator.
5110        strategy_number: u64,
5111        /// Operator name referenced by this entry.
5112        operator_name: ObjectName,
5113        /// Operator argument types.
5114        op_types: Vec<DataType>,
5115        /// Optional purpose such as `FOR SEARCH` or `FOR ORDER BY`.
5116        purpose: Option<OperatorPurpose>,
5117    },
5118    /// `FUNCTION` clause in an operator family modification.
5119    Function {
5120        /// Support function number.
5121        support_number: u64,
5122        /// Optional operator argument types for the function.
5123        op_types: Option<Vec<DataType>>,
5124        /// Function name for the support function.
5125        function_name: ObjectName,
5126        /// Function argument types.
5127        argument_types: Vec<DataType>,
5128    },
5129}
5130
5131/// An item in an ALTER OPERATOR FAMILY DROP statement
5132#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5133#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5134#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5135pub enum OperatorFamilyDropItem {
5136    /// `OPERATOR` clause for DROP within an operator family.
5137    Operator {
5138        /// Strategy number for the operator.
5139        strategy_number: u64,
5140        /// Operator argument types.
5141        op_types: Vec<DataType>,
5142    },
5143    /// `FUNCTION` clause for DROP within an operator family.
5144    Function {
5145        /// Support function number.
5146        support_number: u64,
5147        /// Operator argument types for the function.
5148        op_types: Vec<DataType>,
5149    },
5150}
5151
5152impl fmt::Display for OperatorFamilyItem {
5153    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5154        match self {
5155            OperatorFamilyItem::Operator {
5156                strategy_number,
5157                operator_name,
5158                op_types,
5159                purpose,
5160            } => {
5161                write!(
5162                    f,
5163                    "OPERATOR {strategy_number} {operator_name} ({})",
5164                    display_comma_separated(op_types)
5165                )?;
5166                if let Some(purpose) = purpose {
5167                    write!(f, " {purpose}")?;
5168                }
5169                Ok(())
5170            }
5171            OperatorFamilyItem::Function {
5172                support_number,
5173                op_types,
5174                function_name,
5175                argument_types,
5176            } => {
5177                write!(f, "FUNCTION {support_number}")?;
5178                if let Some(types) = op_types {
5179                    write!(f, " ({})", display_comma_separated(types))?;
5180                }
5181                write!(f, " {function_name}")?;
5182                if !argument_types.is_empty() {
5183                    write!(f, "({})", display_comma_separated(argument_types))?;
5184                }
5185                Ok(())
5186            }
5187        }
5188    }
5189}
5190
5191impl fmt::Display for OperatorFamilyDropItem {
5192    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5193        match self {
5194            OperatorFamilyDropItem::Operator {
5195                strategy_number,
5196                op_types,
5197            } => {
5198                write!(
5199                    f,
5200                    "OPERATOR {strategy_number} ({})",
5201                    display_comma_separated(op_types)
5202                )
5203            }
5204            OperatorFamilyDropItem::Function {
5205                support_number,
5206                op_types,
5207            } => {
5208                write!(
5209                    f,
5210                    "FUNCTION {support_number} ({})",
5211                    display_comma_separated(op_types)
5212                )
5213            }
5214        }
5215    }
5216}
5217
5218/// `ALTER OPERATOR FAMILY` statement
5219/// See <https://www.postgresql.org/docs/current/sql-alteropfamily.html>
5220#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5221#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5222#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5223pub struct AlterOperatorFamily {
5224    /// Operator family name (can be schema-qualified)
5225    pub name: ObjectName,
5226    /// Index method (btree, hash, gist, gin, etc.)
5227    pub using: Ident,
5228    /// The operation to perform
5229    pub operation: AlterOperatorFamilyOperation,
5230}
5231
5232/// An [AlterOperatorFamily] operation
5233#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5234#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5235#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5236pub enum AlterOperatorFamilyOperation {
5237    /// `ADD { OPERATOR ... | FUNCTION ... } [, ...]`
5238    Add {
5239        /// List of operator family items to add
5240        items: Vec<OperatorFamilyItem>,
5241    },
5242    /// `DROP { OPERATOR ... | FUNCTION ... } [, ...]`
5243    Drop {
5244        /// List of operator family items to drop
5245        items: Vec<OperatorFamilyDropItem>,
5246    },
5247    /// `RENAME TO new_name`
5248    RenameTo {
5249        /// The new name for the operator family.
5250        new_name: ObjectName,
5251    },
5252    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
5253    OwnerTo(Owner),
5254    /// `SET SCHEMA new_schema`
5255    SetSchema {
5256        /// The target schema name.
5257        schema_name: ObjectName,
5258    },
5259}
5260
5261impl fmt::Display for AlterOperatorFamily {
5262    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5263        write!(
5264            f,
5265            "ALTER OPERATOR FAMILY {} USING {}",
5266            self.name, self.using
5267        )?;
5268        write!(f, " {}", self.operation)
5269    }
5270}
5271
5272impl fmt::Display for AlterOperatorFamilyOperation {
5273    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5274        match self {
5275            AlterOperatorFamilyOperation::Add { items } => {
5276                write!(f, "ADD {}", display_comma_separated(items))
5277            }
5278            AlterOperatorFamilyOperation::Drop { items } => {
5279                write!(f, "DROP {}", display_comma_separated(items))
5280            }
5281            AlterOperatorFamilyOperation::RenameTo { new_name } => {
5282                write!(f, "RENAME TO {new_name}")
5283            }
5284            AlterOperatorFamilyOperation::OwnerTo(owner) => {
5285                write!(f, "OWNER TO {owner}")
5286            }
5287            AlterOperatorFamilyOperation::SetSchema { schema_name } => {
5288                write!(f, "SET SCHEMA {schema_name}")
5289            }
5290        }
5291    }
5292}
5293
5294impl Spanned for AlterOperatorFamily {
5295    fn span(&self) -> Span {
5296        Span::empty()
5297    }
5298}
5299
5300/// `ALTER OPERATOR CLASS` statement
5301/// See <https://www.postgresql.org/docs/current/sql-alteropclass.html>
5302#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5303#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5304#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5305pub struct AlterOperatorClass {
5306    /// Operator class name (can be schema-qualified)
5307    pub name: ObjectName,
5308    /// Index method (btree, hash, gist, gin, etc.)
5309    pub using: Ident,
5310    /// The operation to perform
5311    pub operation: AlterOperatorClassOperation,
5312}
5313
5314/// An [AlterOperatorClass] operation
5315#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5316#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5317#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5318pub enum AlterOperatorClassOperation {
5319    /// `RENAME TO new_name`
5320    /// Rename the operator class to a new name.
5321    RenameTo {
5322        /// The new name for the operator class.
5323        new_name: ObjectName,
5324    },
5325    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
5326    OwnerTo(Owner),
5327    /// `SET SCHEMA new_schema`
5328    /// Set the schema for the operator class.
5329    SetSchema {
5330        /// The target schema name.
5331        schema_name: ObjectName,
5332    },
5333}
5334
5335impl fmt::Display for AlterOperatorClass {
5336    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5337        write!(f, "ALTER OPERATOR CLASS {} USING {}", self.name, self.using)?;
5338        write!(f, " {}", self.operation)
5339    }
5340}
5341
5342impl fmt::Display for AlterOperatorClassOperation {
5343    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5344        match self {
5345            AlterOperatorClassOperation::RenameTo { new_name } => {
5346                write!(f, "RENAME TO {new_name}")
5347            }
5348            AlterOperatorClassOperation::OwnerTo(owner) => {
5349                write!(f, "OWNER TO {owner}")
5350            }
5351            AlterOperatorClassOperation::SetSchema { schema_name } => {
5352                write!(f, "SET SCHEMA {schema_name}")
5353            }
5354        }
5355    }
5356}
5357
5358impl Spanned for AlterOperatorClass {
5359    fn span(&self) -> Span {
5360        Span::empty()
5361    }
5362}
5363
5364/// `ALTER FUNCTION` / `ALTER AGGREGATE` statement.
5365#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5366#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5367#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5368pub struct AlterFunction {
5369    /// Object type being altered.
5370    pub kind: AlterFunctionKind,
5371    /// Function or aggregate signature.
5372    pub function: FunctionDesc,
5373    /// `ORDER BY` argument list for aggregate signatures.
5374    ///
5375    /// This is only used for `ALTER AGGREGATE`.
5376    pub aggregate_order_by: Option<Vec<OperateFunctionArg>>,
5377    /// Whether the aggregate signature uses `*`.
5378    ///
5379    /// This is only used for `ALTER AGGREGATE`.
5380    pub aggregate_star: bool,
5381    /// Operation applied to the object.
5382    pub operation: AlterFunctionOperation,
5383}
5384
5385/// Function-like object type used by [`AlterFunction`].
5386#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5387#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5388#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5389pub enum AlterFunctionKind {
5390    /// `FUNCTION`
5391    Function,
5392    /// `AGGREGATE`
5393    Aggregate,
5394}
5395
5396impl fmt::Display for AlterFunctionKind {
5397    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5398        match self {
5399            Self::Function => write!(f, "FUNCTION"),
5400            Self::Aggregate => write!(f, "AGGREGATE"),
5401        }
5402    }
5403}
5404
5405/// Operation for `ALTER FUNCTION` / `ALTER AGGREGATE`.
5406#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5407#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5408#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5409pub enum AlterFunctionOperation {
5410    /// `RENAME TO new_name`
5411    RenameTo {
5412        /// New unqualified function or aggregate name.
5413        new_name: Ident,
5414    },
5415    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
5416    OwnerTo(Owner),
5417    /// `SET SCHEMA schema_name`
5418    SetSchema {
5419        /// The target schema name.
5420        schema_name: ObjectName,
5421    },
5422    /// `[ NO ] DEPENDS ON EXTENSION extension_name`
5423    DependsOnExtension {
5424        /// `true` when `NO DEPENDS ON EXTENSION`.
5425        no: bool,
5426        /// Extension name.
5427        extension_name: ObjectName,
5428    },
5429    /// `action [ ... ] [ RESTRICT ]` (function only).
5430    Actions {
5431        /// One or more function actions.
5432        actions: Vec<AlterFunctionAction>,
5433        /// Whether `RESTRICT` is present.
5434        restrict: bool,
5435    },
5436}
5437
5438/// Function action in `ALTER FUNCTION ... action [ ... ] [ RESTRICT ]`.
5439#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5440#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5441#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5442pub enum AlterFunctionAction {
5443    /// `CALLED ON NULL INPUT` / `RETURNS NULL ON NULL INPUT` / `STRICT`
5444    CalledOnNull(FunctionCalledOnNull),
5445    /// `IMMUTABLE` / `STABLE` / `VOLATILE`
5446    Behavior(FunctionBehavior),
5447    /// `[ NOT ] LEAKPROOF`
5448    Leakproof(bool),
5449    /// `[ EXTERNAL ] SECURITY { DEFINER | INVOKER }`
5450    Security {
5451        /// Whether the optional `EXTERNAL` keyword was present.
5452        external: bool,
5453        /// Security mode.
5454        security: FunctionSecurity,
5455    },
5456    /// `PARALLEL { UNSAFE | RESTRICTED | SAFE }`
5457    Parallel(FunctionParallel),
5458    /// `COST execution_cost`
5459    Cost(Expr),
5460    /// `ROWS result_rows`
5461    Rows(Expr),
5462    /// `SUPPORT support_function`
5463    Support(ObjectName),
5464    /// `SET configuration_parameter { TO | = } { value | DEFAULT }`
5465    /// or `SET configuration_parameter FROM CURRENT`
5466    Set(FunctionDefinitionSetParam),
5467    /// `RESET configuration_parameter` or `RESET ALL`
5468    Reset(ResetConfig),
5469}
5470
5471impl fmt::Display for AlterFunction {
5472    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5473        write!(f, "ALTER {} ", self.kind)?;
5474        match self.kind {
5475            AlterFunctionKind::Function => {
5476                write!(f, "{} ", self.function)?;
5477            }
5478            AlterFunctionKind::Aggregate => {
5479                write!(f, "{}(", self.function.name)?;
5480                if self.aggregate_star {
5481                    write!(f, "*")?;
5482                } else {
5483                    if let Some(args) = &self.function.args {
5484                        write!(f, "{}", display_comma_separated(args))?;
5485                    }
5486                    if let Some(order_by_args) = &self.aggregate_order_by {
5487                        if self
5488                            .function
5489                            .args
5490                            .as_ref()
5491                            .is_some_and(|args| !args.is_empty())
5492                        {
5493                            write!(f, " ")?;
5494                        }
5495                        write!(f, "ORDER BY {}", display_comma_separated(order_by_args))?;
5496                    }
5497                }
5498                write!(f, ") ")?;
5499            }
5500        }
5501        write!(f, "{}", self.operation)
5502    }
5503}
5504
5505impl fmt::Display for AlterFunctionOperation {
5506    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5507        match self {
5508            AlterFunctionOperation::RenameTo { new_name } => {
5509                write!(f, "RENAME TO {new_name}")
5510            }
5511            AlterFunctionOperation::OwnerTo(owner) => write!(f, "OWNER TO {owner}"),
5512            AlterFunctionOperation::SetSchema { schema_name } => {
5513                write!(f, "SET SCHEMA {schema_name}")
5514            }
5515            AlterFunctionOperation::DependsOnExtension { no, extension_name } => {
5516                if *no {
5517                    write!(f, "NO DEPENDS ON EXTENSION {extension_name}")
5518                } else {
5519                    write!(f, "DEPENDS ON EXTENSION {extension_name}")
5520                }
5521            }
5522            AlterFunctionOperation::Actions { actions, restrict } => {
5523                write!(f, "{}", display_separated(actions, " "))?;
5524                if *restrict {
5525                    write!(f, " RESTRICT")?;
5526                }
5527                Ok(())
5528            }
5529        }
5530    }
5531}
5532
5533impl fmt::Display for AlterFunctionAction {
5534    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5535        match self {
5536            AlterFunctionAction::CalledOnNull(called_on_null) => write!(f, "{called_on_null}"),
5537            AlterFunctionAction::Behavior(behavior) => write!(f, "{behavior}"),
5538            AlterFunctionAction::Leakproof(leakproof) => {
5539                if *leakproof {
5540                    write!(f, "LEAKPROOF")
5541                } else {
5542                    write!(f, "NOT LEAKPROOF")
5543                }
5544            }
5545            AlterFunctionAction::Security { external, security } => {
5546                if *external {
5547                    write!(f, "EXTERNAL ")?;
5548                }
5549                write!(f, "{security}")
5550            }
5551            AlterFunctionAction::Parallel(parallel) => write!(f, "{parallel}"),
5552            AlterFunctionAction::Cost(execution_cost) => write!(f, "COST {execution_cost}"),
5553            AlterFunctionAction::Rows(result_rows) => write!(f, "ROWS {result_rows}"),
5554            AlterFunctionAction::Support(support_function) => {
5555                write!(f, "SUPPORT {support_function}")
5556            }
5557            AlterFunctionAction::Set(set_param) => write!(f, "{set_param}"),
5558            AlterFunctionAction::Reset(reset_config) => match reset_config {
5559                ResetConfig::ALL => write!(f, "RESET ALL"),
5560                ResetConfig::ConfigName(name) => write!(f, "RESET {name}"),
5561            },
5562        }
5563    }
5564}
5565
5566impl Spanned for AlterFunction {
5567    fn span(&self) -> Span {
5568        Span::empty()
5569    }
5570}
5571
5572/// CREATE POLICY statement.
5573///
5574/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createpolicy.html)
5575#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5576#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5577#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5578pub struct CreatePolicy {
5579    /// Name of the policy.
5580    pub name: Ident,
5581    /// Table the policy is defined on.
5582    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
5583    pub table_name: ObjectName,
5584    /// Optional policy type (e.g., `PERMISSIVE` / `RESTRICTIVE`).
5585    pub policy_type: Option<CreatePolicyType>,
5586    /// Optional command the policy applies to (e.g., `SELECT`).
5587    pub command: Option<CreatePolicyCommand>,
5588    /// Optional list of grantee owners.
5589    pub to: Option<Vec<Owner>>,
5590    /// Optional expression for the `USING` clause.
5591    pub using: Option<Expr>,
5592    /// Optional expression for the `WITH CHECK` clause.
5593    pub with_check: Option<Expr>,
5594}
5595
5596impl fmt::Display for CreatePolicy {
5597    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5598        write!(
5599            f,
5600            "CREATE POLICY {name} ON {table_name}",
5601            name = self.name,
5602            table_name = self.table_name,
5603        )?;
5604        if let Some(ref policy_type) = self.policy_type {
5605            write!(f, " AS {policy_type}")?;
5606        }
5607        if let Some(ref command) = self.command {
5608            write!(f, " FOR {command}")?;
5609        }
5610        if let Some(ref to) = self.to {
5611            write!(f, " TO {}", display_comma_separated(to))?;
5612        }
5613        if let Some(ref using) = self.using {
5614            write!(f, " USING ({using})")?;
5615        }
5616        if let Some(ref with_check) = self.with_check {
5617            write!(f, " WITH CHECK ({with_check})")?;
5618        }
5619        Ok(())
5620    }
5621}
5622
5623/// Policy type for a `CREATE POLICY` statement.
5624/// ```sql
5625/// AS [ PERMISSIVE | RESTRICTIVE ]
5626/// ```
5627/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createpolicy.html)
5628#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
5629#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5630#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5631pub enum CreatePolicyType {
5632    /// Policy allows operations unless explicitly denied.
5633    Permissive,
5634    /// Policy denies operations unless explicitly allowed.
5635    Restrictive,
5636}
5637
5638impl fmt::Display for CreatePolicyType {
5639    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5640        match self {
5641            CreatePolicyType::Permissive => write!(f, "PERMISSIVE"),
5642            CreatePolicyType::Restrictive => write!(f, "RESTRICTIVE"),
5643        }
5644    }
5645}
5646
5647/// Command that a policy can apply to (FOR clause).
5648/// ```sql
5649/// FOR [ALL | SELECT | INSERT | UPDATE | DELETE]
5650/// ```
5651/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createpolicy.html)
5652#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
5653#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5654#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5655pub enum CreatePolicyCommand {
5656    /// Applies to all commands.
5657    All,
5658    /// Applies to SELECT.
5659    Select,
5660    /// Applies to INSERT.
5661    Insert,
5662    /// Applies to UPDATE.
5663    Update,
5664    /// Applies to DELETE.
5665    Delete,
5666}
5667
5668impl fmt::Display for CreatePolicyCommand {
5669    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5670        match self {
5671            CreatePolicyCommand::All => write!(f, "ALL"),
5672            CreatePolicyCommand::Select => write!(f, "SELECT"),
5673            CreatePolicyCommand::Insert => write!(f, "INSERT"),
5674            CreatePolicyCommand::Update => write!(f, "UPDATE"),
5675            CreatePolicyCommand::Delete => write!(f, "DELETE"),
5676        }
5677    }
5678}
5679
5680/// DROP POLICY statement.
5681///
5682/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-droppolicy.html)
5683#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5684#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5685#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5686pub struct DropPolicy {
5687    /// `true` when `IF EXISTS` was present.
5688    pub if_exists: bool,
5689    /// Name of the policy to drop.
5690    pub name: Ident,
5691    /// Name of the table the policy applies to.
5692    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
5693    pub table_name: ObjectName,
5694    /// Optional drop behavior (`CASCADE` or `RESTRICT`).
5695    pub drop_behavior: Option<DropBehavior>,
5696}
5697
5698impl fmt::Display for DropPolicy {
5699    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5700        write!(
5701            f,
5702            "DROP POLICY {if_exists}{name} ON {table_name}",
5703            if_exists = if self.if_exists { "IF EXISTS " } else { "" },
5704            name = self.name,
5705            table_name = self.table_name
5706        )?;
5707        if let Some(ref behavior) = self.drop_behavior {
5708            write!(f, " {behavior}")?;
5709        }
5710        Ok(())
5711    }
5712}
5713
5714impl From<CreatePolicy> for crate::ast::Statement {
5715    fn from(v: CreatePolicy) -> Self {
5716        crate::ast::Statement::CreatePolicy(v)
5717    }
5718}
5719
5720impl From<DropPolicy> for crate::ast::Statement {
5721    fn from(v: DropPolicy) -> Self {
5722        crate::ast::Statement::DropPolicy(v)
5723    }
5724}
5725
5726/// ALTER POLICY statement.
5727///
5728/// ```sql
5729/// ALTER POLICY <NAME> ON <TABLE NAME> [<OPERATION>]
5730/// ```
5731/// (Postgresql-specific)
5732#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5733#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5734#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5735pub struct AlterPolicy {
5736    /// Policy name to alter.
5737    pub name: Ident,
5738    /// Target table name the policy is defined on.
5739    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
5740    pub table_name: ObjectName,
5741    /// Optional operation specific to the policy alteration.
5742    pub operation: AlterPolicyOperation,
5743}
5744
5745impl fmt::Display for AlterPolicy {
5746    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5747        write!(
5748            f,
5749            "ALTER POLICY {name} ON {table_name}{operation}",
5750            name = self.name,
5751            table_name = self.table_name,
5752            operation = self.operation
5753        )
5754    }
5755}
5756
5757impl From<AlterPolicy> for crate::ast::Statement {
5758    fn from(v: AlterPolicy) -> Self {
5759        crate::ast::Statement::AlterPolicy(v)
5760    }
5761}