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