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,
47    FileFormat, FunctionBehavior, FunctionCalledOnNull, FunctionDefinitionSetParam, FunctionDesc,
48    FunctionDeterminismSpecifier, FunctionParallel, FunctionSecurity, HiveDistributionStyle,
49    HiveFormat, HiveIOFormat, HiveRowFormat, HiveSetLocation, Ident, InitializeKind,
50    MySQLColumnPosition, ObjectName, OnCommit, OneOrManyWithParens, OperateFunctionArg,
51    OrderByExpr, ProjectionSelect, Query, RefreshModeKind, ResetConfig, RowAccessPolicy,
52    SequenceOptions, Spanned, SqlOption, StorageLifecyclePolicy, StorageSerializationPolicy,
53    TableVersion, Tag, TriggerEvent, TriggerExecBody, TriggerObject, TriggerPeriod,
54    TriggerReferencing, Value, ValueWithSpan, WrappedCollection,
55};
56use crate::display_utils::{DisplayCommaSeparated, Indent, NewLine, SpaceOrNewline};
57use crate::keywords::Keyword;
58use crate::tokenizer::{Span, Token};
59
60/// Index column type.
61#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
62#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
63#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
64pub struct IndexColumn {
65    /// The indexed column expression.
66    pub column: OrderByExpr,
67    /// Optional operator class (index operator name).
68    pub operator_class: Option<ObjectName>,
69}
70
71impl From<Ident> for IndexColumn {
72    fn from(c: Ident) -> Self {
73        Self {
74            column: OrderByExpr::from(c),
75            operator_class: None,
76        }
77    }
78}
79
80impl<'a> From<&'a str> for IndexColumn {
81    fn from(c: &'a str) -> Self {
82        let ident = Ident::new(c);
83        ident.into()
84    }
85}
86
87impl fmt::Display for IndexColumn {
88    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89        write!(f, "{}", self.column)?;
90        if let Some(operator_class) = &self.operator_class {
91            write!(f, " {operator_class}")?;
92        }
93        Ok(())
94    }
95}
96
97/// ALTER TABLE operation REPLICA IDENTITY values
98/// See [Postgres ALTER TABLE docs](https://www.postgresql.org/docs/current/sql-altertable.html)
99#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
100#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
101#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
102pub enum ReplicaIdentity {
103    /// No replica identity (`REPLICA IDENTITY NOTHING`).
104    Nothing,
105    /// Full replica identity (`REPLICA IDENTITY FULL`).
106    Full,
107    /// Default replica identity (`REPLICA IDENTITY DEFAULT`).
108    Default,
109    /// Use the given index as replica identity (`REPLICA IDENTITY USING INDEX`).
110    Index(Ident),
111}
112
113impl fmt::Display for ReplicaIdentity {
114    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115        match self {
116            ReplicaIdentity::Nothing => f.write_str("NOTHING"),
117            ReplicaIdentity::Full => f.write_str("FULL"),
118            ReplicaIdentity::Default => f.write_str("DEFAULT"),
119            ReplicaIdentity::Index(idx) => write!(f, "USING INDEX {idx}"),
120        }
121    }
122}
123
124/// An `ALTER TABLE` (`Statement::AlterTable`) operation
125#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
126#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
127#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
128pub enum AlterTableOperation {
129    /// `ADD <table_constraint> [NOT VALID]`
130    AddConstraint {
131        /// The table constraint to add.
132        constraint: TableConstraint,
133        /// Whether the constraint should be marked `NOT VALID`.
134        not_valid: bool,
135    },
136    /// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
137    AddColumn {
138        /// `[COLUMN]`.
139        column_keyword: bool,
140        /// `[IF NOT EXISTS]`
141        if_not_exists: bool,
142        /// <column_def>.
143        column_def: ColumnDef,
144        /// MySQL `ALTER TABLE` only  [FIRST | AFTER column_name]
145        column_position: Option<MySQLColumnPosition>,
146    },
147    /// `ADD PROJECTION [IF NOT EXISTS] name ( SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY])`
148    ///
149    /// Note: this is a ClickHouse-specific operation.
150    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#add-projection)
151    AddProjection {
152        /// Whether `IF NOT EXISTS` was specified.
153        if_not_exists: bool,
154        /// Name of the projection to add.
155        name: Ident,
156        /// The projection's select clause.
157        select: ProjectionSelect,
158    },
159    /// `DROP PROJECTION [IF EXISTS] name`
160    ///
161    /// Note: this is a ClickHouse-specific operation.
162    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#drop-projection)
163    DropProjection {
164        /// Whether `IF EXISTS` was specified.
165        if_exists: bool,
166        /// Name of the projection to drop.
167        name: Ident,
168    },
169    /// `MATERIALIZE PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
170    ///
171    ///  Note: this is a ClickHouse-specific operation.
172    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#materialize-projection)
173    MaterializeProjection {
174        /// Whether `IF EXISTS` was specified.
175        if_exists: bool,
176        /// Name of the projection to materialize.
177        name: Ident,
178        /// Optional partition name to operate on.
179        partition: Option<Ident>,
180    },
181    /// `CLEAR PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
182    ///
183    /// Note: this is a ClickHouse-specific operation.
184    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#clear-projection)
185    ClearProjection {
186        /// Whether `IF EXISTS` was specified.
187        if_exists: bool,
188        /// Name of the projection to clear.
189        name: Ident,
190        /// Optional partition name to operate on.
191        partition: Option<Ident>,
192    },
193    /// `DISABLE ROW LEVEL SECURITY`
194    ///
195    /// Note: this is a PostgreSQL-specific operation.
196    /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
197    DisableRowLevelSecurity,
198    /// `DISABLE RULE rewrite_rule_name`
199    ///
200    /// Note: this is a PostgreSQL-specific operation.
201    DisableRule {
202        /// Name of the rule to disable.
203        name: Ident,
204    },
205    /// `DISABLE TRIGGER [ trigger_name | ALL | USER ]`
206    ///
207    /// Note: this is a PostgreSQL-specific operation.
208    DisableTrigger {
209        /// Name of the trigger to disable (or ALL/USER).
210        name: Ident,
211    },
212    /// `DROP CONSTRAINT [ IF EXISTS ] <name>`
213    DropConstraint {
214        /// `IF EXISTS` flag for dropping the constraint.
215        if_exists: bool,
216        /// Name of the constraint to drop.
217        name: Ident,
218        /// Optional drop behavior (`CASCADE`/`RESTRICT`).
219        drop_behavior: Option<DropBehavior>,
220    },
221    /// `DROP [ COLUMN ] [ IF EXISTS ] <column_name> [ , <column_name>, ... ] [ CASCADE ]`
222    DropColumn {
223        /// Whether the `COLUMN` keyword was present.
224        has_column_keyword: bool,
225        /// Names of columns to drop.
226        column_names: Vec<Ident>,
227        /// Whether `IF EXISTS` was specified for the columns.
228        if_exists: bool,
229        /// Optional drop behavior for the column removal.
230        drop_behavior: Option<DropBehavior>,
231    },
232    /// `ATTACH PART|PARTITION <partition_expr>`
233    /// Note: this is a ClickHouse-specific operation, please refer to
234    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
235    AttachPartition {
236        // PART is not a short form of PARTITION, it's a separate keyword
237        // which represents a physical file on disk and partition is a logical entity.
238        /// Partition expression to attach.
239        partition: Partition,
240    },
241    /// `DETACH PART|PARTITION <partition_expr>`
242    /// Note: this is a ClickHouse-specific operation, please refer to
243    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#detach-partitionpart)
244    DetachPartition {
245        // See `AttachPartition` for more details
246        /// Partition expression to detach.
247        partition: Partition,
248    },
249    /// `ATTACH PARTITION <partition_name> { FOR VALUES <partition_bound_spec> | DEFAULT }`
250    ///
251    /// PostgreSQL-specific operation for declarative partitioning.
252    /// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-altertable.html)
253    AttachPartitionOf {
254        /// Name of the partition table to attach.
255        partition_name: ObjectName,
256        /// Partition bound specification, or DEFAULT.
257        partition_bound: ForValues,
258    },
259    /// `DETACH PARTITION <partition_name> [ CONCURRENTLY | FINALIZE ]`
260    ///
261    /// PostgreSQL-specific operation for declarative partitioning.
262    /// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-altertable.html)
263    DetachPartitionOf {
264        /// Name of the partition table to detach.
265        partition_name: ObjectName,
266        /// Whether to detach concurrently (non-blocking two-phase detach).
267        concurrently: bool,
268        /// Whether to finalize a previously started concurrent detach.
269        finalize: bool,
270    },
271    /// `FREEZE PARTITION <partition_expr>`
272    /// Note: this is a ClickHouse-specific operation, please refer to
273    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#freeze-partition)
274    FreezePartition {
275        /// Partition to freeze.
276        partition: Partition,
277        /// Optional name for the freeze operation.
278        with_name: Option<Ident>,
279    },
280    /// `UNFREEZE PARTITION <partition_expr>`
281    /// Note: this is a ClickHouse-specific operation, please refer to
282    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#unfreeze-partition)
283    UnfreezePartition {
284        /// Partition to unfreeze.
285        partition: Partition,
286        /// Optional name associated with the unfreeze operation.
287        with_name: Option<Ident>,
288    },
289    /// `DROP PRIMARY KEY`
290    ///
291    /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/alter-table.html)
292    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constraints-drop)
293    DropPrimaryKey {
294        /// Optional drop behavior for the primary key (`CASCADE`/`RESTRICT`).
295        drop_behavior: Option<DropBehavior>,
296    },
297    /// `DROP FOREIGN KEY <fk_symbol>`
298    ///
299    /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/alter-table.html)
300    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constraints-drop)
301    DropForeignKey {
302        /// Foreign key symbol/name to drop.
303        name: Ident,
304        /// Optional drop behavior for the foreign key.
305        drop_behavior: Option<DropBehavior>,
306    },
307    /// `DROP INDEX <index_name>`
308    ///
309    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
310    DropIndex {
311        /// Name of the index to drop.
312        name: Ident,
313    },
314    /// `ENABLE ALWAYS RULE rewrite_rule_name`
315    ///
316    /// Note: this is a PostgreSQL-specific operation.
317    EnableAlwaysRule {
318        /// Name of the rule to enable.
319        name: Ident,
320    },
321    /// `ENABLE ALWAYS TRIGGER trigger_name`
322    ///
323    /// Note: this is a PostgreSQL-specific operation.
324    EnableAlwaysTrigger {
325        /// Name of the trigger to enable.
326        name: Ident,
327    },
328    /// `ENABLE REPLICA RULE rewrite_rule_name`
329    ///
330    /// Note: this is a PostgreSQL-specific operation.
331    EnableReplicaRule {
332        /// Name of the replica rule to enable.
333        name: Ident,
334    },
335    /// `ENABLE REPLICA TRIGGER trigger_name`
336    ///
337    /// Note: this is a PostgreSQL-specific operation.
338    EnableReplicaTrigger {
339        /// Name of the replica trigger to enable.
340        name: Ident,
341    },
342    /// `ENABLE ROW LEVEL SECURITY`
343    ///
344    /// Note: this is a PostgreSQL-specific operation.
345    /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
346    EnableRowLevelSecurity,
347    /// `FORCE ROW LEVEL SECURITY`
348    ///
349    /// Note: this is a PostgreSQL-specific operation.
350    /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
351    ForceRowLevelSecurity,
352    /// `NO FORCE ROW LEVEL SECURITY`
353    ///
354    /// Note: this is a PostgreSQL-specific operation.
355    /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
356    NoForceRowLevelSecurity,
357    /// `ENABLE RULE rewrite_rule_name`
358    ///
359    /// Note: this is a PostgreSQL-specific operation.
360    EnableRule {
361        /// Name of the rule to enable.
362        name: Ident,
363    },
364    /// `ENABLE TRIGGER [ trigger_name | ALL | USER ]`
365    ///
366    /// Note: this is a PostgreSQL-specific operation.
367    EnableTrigger {
368        /// Name of the trigger to enable (or ALL/USER).
369        name: Ident,
370    },
371    /// `RENAME TO PARTITION (partition=val)`
372    RenamePartitions {
373        /// Old partition expressions to be renamed.
374        old_partitions: Vec<Expr>,
375        /// New partition expressions corresponding to the old ones.
376        new_partitions: Vec<Expr>,
377    },
378    /// REPLICA IDENTITY { DEFAULT | USING INDEX index_name | FULL | NOTHING }
379    ///
380    /// Note: this is a PostgreSQL-specific operation.
381    /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
382    ReplicaIdentity {
383        /// Replica identity setting to apply.
384        identity: ReplicaIdentity,
385    },
386    /// Add Partitions
387    AddPartitions {
388        /// Whether `IF NOT EXISTS` was present when adding partitions.
389        if_not_exists: bool,
390        /// New partitions to add.
391        new_partitions: Vec<Partition>,
392    },
393    /// `DROP PARTITIONS ...` / drop partitions from the table.
394    DropPartitions {
395        /// Partitions to drop (expressions).
396        partitions: Vec<Expr>,
397        /// Whether `IF EXISTS` was specified for dropping partitions.
398        if_exists: bool,
399    },
400    /// `RENAME [ COLUMN ] <old_column_name> TO <new_column_name>`
401    RenameColumn {
402        /// Existing column name to rename.
403        old_column_name: Ident,
404        /// New column name.
405        new_column_name: Ident,
406    },
407    /// `RENAME TO <table_name>`
408    RenameTable {
409        /// The new table name or renaming kind.
410        table_name: RenameTableNameKind,
411    },
412    // CHANGE [ COLUMN ] <old_name> <new_name> <data_type> [ <options> ]
413    /// Change an existing column's name, type, and options.
414    ChangeColumn {
415        /// Old column name.
416        old_name: Ident,
417        /// New column name.
418        new_name: Ident,
419        /// New data type for the column.
420        data_type: DataType,
421        /// Column options to apply after the change.
422        options: Vec<ColumnOption>,
423        /// MySQL-specific column position (`FIRST`/`AFTER`).
424        column_position: Option<MySQLColumnPosition>,
425    },
426    // CHANGE [ COLUMN ] <col_name> <data_type> [ <options> ]
427    /// Modify an existing column's type and options.
428    ModifyColumn {
429        /// Column name to modify.
430        col_name: Ident,
431        /// New data type for the column.
432        data_type: DataType,
433        /// Column options to set.
434        options: Vec<ColumnOption>,
435        /// MySQL-specific column position (`FIRST`/`AFTER`).
436        column_position: Option<MySQLColumnPosition>,
437    },
438    /// `RENAME CONSTRAINT <old_constraint_name> TO <new_constraint_name>`
439    ///
440    /// Note: this is a PostgreSQL-specific operation.
441    /// Rename a constraint on the table.
442    RenameConstraint {
443        /// Existing constraint name.
444        old_name: Ident,
445        /// New constraint name.
446        new_name: Ident,
447    },
448    /// `ALTER [ COLUMN ]`
449    /// Alter a specific column with the provided operation.
450    AlterColumn {
451        /// The column to alter.
452        column_name: Ident,
453        /// Operation to apply to the column.
454        op: AlterColumnOperation,
455    },
456    /// 'SWAP WITH <table_name>'
457    ///
458    /// Note: this is Snowflake specific <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
459    SwapWith {
460        /// Table name to swap with.
461        table_name: ObjectName,
462    },
463    /// 'SET TBLPROPERTIES ( { property_key [ = ] property_val } [, ...] )'
464    SetTblProperties {
465        /// Table properties specified as SQL options.
466        table_properties: Vec<SqlOption>,
467    },
468    /// `OWNER TO { <new_owner> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
469    ///
470    /// Note: this is PostgreSQL-specific <https://www.postgresql.org/docs/current/sql-altertable.html>
471    OwnerTo {
472        /// The new owner to assign to the table.
473        new_owner: Owner,
474    },
475    /// Snowflake table clustering options
476    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-table#clustering-actions-clusteringaction>
477    ClusterBy {
478        /// Expressions used for clustering the table.
479        exprs: Vec<Expr>,
480    },
481    /// Remove the clustering key from the table.
482    DropClusteringKey,
483    /// Redshift `ALTER SORTKEY (column_list)`
484    /// <https://docs.aws.amazon.com/redshift/latest/dg/r_ALTER_TABLE.html>
485    AlterSortKey {
486        /// Column references in the sort key.
487        columns: Vec<Expr>,
488    },
489    /// Suspend background reclustering operations.
490    SuspendRecluster,
491    /// Resume background reclustering operations.
492    ResumeRecluster,
493    /// `REFRESH [ '<subpath>' ]`
494    ///
495    /// Note: this is Snowflake specific for dynamic/external tables
496    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-dynamic-table>
497    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
498    Refresh {
499        /// Optional subpath for external table refresh
500        subpath: Option<String>,
501    },
502    /// `SUSPEND`
503    ///
504    /// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
505    Suspend,
506    /// `RESUME`
507    ///
508    /// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
509    Resume,
510    /// `ALGORITHM [=] { DEFAULT | INSTANT | INPLACE | COPY }`
511    ///
512    /// [MySQL]-specific table alter algorithm.
513    ///
514    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
515    Algorithm {
516        /// Whether the `=` sign was used (`ALGORITHM = ...`).
517        equals: bool,
518        /// The algorithm to use for the alter operation (MySQL-specific).
519        algorithm: AlterTableAlgorithm,
520    },
521
522    /// `LOCK [=] { DEFAULT | NONE | SHARED | EXCLUSIVE }`
523    ///
524    /// [MySQL]-specific table alter lock.
525    ///
526    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
527    Lock {
528        /// Whether the `=` sign was used (`LOCK = ...`).
529        equals: bool,
530        /// The locking behavior to apply (MySQL-specific).
531        lock: AlterTableLock,
532    },
533    /// `AUTO_INCREMENT [=] <value>`
534    ///
535    /// [MySQL]-specific table option for raising current auto increment value.
536    ///
537    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
538    AutoIncrement {
539        /// Whether the `=` sign was used (`AUTO_INCREMENT = ...`).
540        equals: bool,
541        /// Value to set for the auto-increment counter.
542        value: ValueWithSpan,
543    },
544    /// `VALIDATE CONSTRAINT <name>`
545    ValidateConstraint {
546        /// Name of the constraint to validate.
547        name: Ident,
548    },
549    /// Arbitrary parenthesized `SET` options.
550    ///
551    /// Example:
552    /// ```sql
553    /// SET (scale_factor = 0.01, threshold = 500)`
554    /// ```
555    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-altertable.html)
556    SetOptionsParens {
557        /// Parenthesized options supplied to `SET (...)`.
558        options: Vec<SqlOption>,
559    },
560    /// `SET TABLESPACE tablespace_name`
561    ///
562    /// Note: this is a PostgreSQL-specific operation.
563    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-altertable.html)
564    SetTablespace {
565        /// The target tablespace name.
566        tablespace_name: Ident,
567    },
568}
569
570/// An `ALTER Policy` (`Statement::AlterPolicy`) operation
571///
572/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
573#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
574#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
575#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
576pub enum AlterPolicyOperation {
577    /// Rename the policy to `new_name`.
578    Rename {
579        /// The new identifier for the policy.
580        new_name: Ident,
581    },
582    /// Apply/modify policy properties.
583    Apply {
584        /// Optional list of owners the policy applies to.
585        to: Option<Vec<Owner>>,
586        /// Optional `USING` expression for the policy.
587        using: Option<Expr>,
588        /// Optional `WITH CHECK` expression for the policy.
589        with_check: Option<Expr>,
590    },
591}
592
593impl fmt::Display for AlterPolicyOperation {
594    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
595        match self {
596            AlterPolicyOperation::Rename { new_name } => {
597                write!(f, " RENAME TO {new_name}")
598            }
599            AlterPolicyOperation::Apply {
600                to,
601                using,
602                with_check,
603            } => {
604                if let Some(to) = to {
605                    write!(f, " TO {}", display_comma_separated(to))?;
606                }
607                if let Some(using) = using {
608                    write!(f, " USING ({using})")?;
609                }
610                if let Some(with_check) = with_check {
611                    write!(f, " WITH CHECK ({with_check})")?;
612                }
613                Ok(())
614            }
615        }
616    }
617}
618
619/// [MySQL] `ALTER TABLE` algorithm.
620///
621/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
622#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
623#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
624#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
625/// Algorithm option for `ALTER TABLE` operations (MySQL-specific).
626pub enum AlterTableAlgorithm {
627    /// Default algorithm selection.
628    Default,
629    /// `INSTANT` algorithm.
630    Instant,
631    /// `INPLACE` algorithm.
632    Inplace,
633    /// `COPY` algorithm.
634    Copy,
635}
636
637impl fmt::Display for AlterTableAlgorithm {
638    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
639        f.write_str(match self {
640            Self::Default => "DEFAULT",
641            Self::Instant => "INSTANT",
642            Self::Inplace => "INPLACE",
643            Self::Copy => "COPY",
644        })
645    }
646}
647
648/// [MySQL] `ALTER TABLE` lock.
649///
650/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
651#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
652#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
653#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
654/// Locking behavior for `ALTER TABLE` (MySQL-specific).
655pub enum AlterTableLock {
656    /// `DEFAULT` lock behavior.
657    Default,
658    /// `NONE` lock.
659    None,
660    /// `SHARED` lock.
661    Shared,
662    /// `EXCLUSIVE` lock.
663    Exclusive,
664}
665
666impl fmt::Display for AlterTableLock {
667    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
668        f.write_str(match self {
669            Self::Default => "DEFAULT",
670            Self::None => "NONE",
671            Self::Shared => "SHARED",
672            Self::Exclusive => "EXCLUSIVE",
673        })
674    }
675}
676
677#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
678#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
679#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
680/// New owner specification for `ALTER TABLE ... OWNER TO ...`
681pub enum Owner {
682    /// A specific user/role identifier.
683    Ident(Ident),
684    /// `CURRENT_ROLE` keyword.
685    CurrentRole,
686    /// `CURRENT_USER` keyword.
687    CurrentUser,
688    /// `SESSION_USER` keyword.
689    SessionUser,
690}
691
692impl fmt::Display for Owner {
693    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
694        match self {
695            Owner::Ident(ident) => write!(f, "{ident}"),
696            Owner::CurrentRole => write!(f, "CURRENT_ROLE"),
697            Owner::CurrentUser => write!(f, "CURRENT_USER"),
698            Owner::SessionUser => write!(f, "SESSION_USER"),
699        }
700    }
701}
702
703#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
704#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
705#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
706/// New connector owner specification for `ALTER CONNECTOR ... OWNER TO ...`
707pub enum AlterConnectorOwner {
708    /// `USER <ident>` connector owner.
709    User(Ident),
710    /// `ROLE <ident>` connector owner.
711    Role(Ident),
712}
713
714impl fmt::Display for AlterConnectorOwner {
715    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
716        match self {
717            AlterConnectorOwner::User(ident) => write!(f, "USER {ident}"),
718            AlterConnectorOwner::Role(ident) => write!(f, "ROLE {ident}"),
719        }
720    }
721}
722
723#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
724#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
725#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
726/// Alterations that can be applied to an index.
727pub enum AlterIndexOperation {
728    /// Rename the index to `index_name`.
729    RenameIndex {
730        /// The new name for the index.
731        index_name: ObjectName,
732    },
733    /// `SET TABLESPACE tablespace_name`
734    ///
735    /// Note: this is a PostgreSQL-specific operation.
736    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterindex.html)
737    SetTablespace {
738        /// The target tablespace name.
739        tablespace_name: Ident,
740    },
741}
742
743impl fmt::Display for AlterTableOperation {
744    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
745        match self {
746            AlterTableOperation::AddPartitions {
747                if_not_exists,
748                new_partitions,
749            } => write!(
750                f,
751                "ADD{ine} {}",
752                display_separated(new_partitions, " "),
753                ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
754            ),
755            AlterTableOperation::AddConstraint {
756                not_valid,
757                constraint,
758            } => {
759                write!(f, "ADD {constraint}")?;
760                if *not_valid {
761                    write!(f, " NOT VALID")?;
762                }
763                Ok(())
764            }
765            AlterTableOperation::AddColumn {
766                column_keyword,
767                if_not_exists,
768                column_def,
769                column_position,
770            } => {
771                write!(f, "ADD")?;
772                if *column_keyword {
773                    write!(f, " COLUMN")?;
774                }
775                if *if_not_exists {
776                    write!(f, " IF NOT EXISTS")?;
777                }
778                write!(f, " {column_def}")?;
779
780                if let Some(position) = column_position {
781                    write!(f, " {position}")?;
782                }
783
784                Ok(())
785            }
786            AlterTableOperation::AddProjection {
787                if_not_exists,
788                name,
789                select: query,
790            } => {
791                write!(f, "ADD PROJECTION")?;
792                if *if_not_exists {
793                    write!(f, " IF NOT EXISTS")?;
794                }
795                write!(f, " {name} ({query})")
796            }
797            AlterTableOperation::Algorithm { equals, algorithm } => {
798                write!(
799                    f,
800                    "ALGORITHM {}{}",
801                    if *equals { "= " } else { "" },
802                    algorithm
803                )
804            }
805            AlterTableOperation::DropProjection { if_exists, name } => {
806                write!(f, "DROP PROJECTION")?;
807                if *if_exists {
808                    write!(f, " IF EXISTS")?;
809                }
810                write!(f, " {name}")
811            }
812            AlterTableOperation::MaterializeProjection {
813                if_exists,
814                name,
815                partition,
816            } => {
817                write!(f, "MATERIALIZE PROJECTION")?;
818                if *if_exists {
819                    write!(f, " IF EXISTS")?;
820                }
821                write!(f, " {name}")?;
822                if let Some(partition) = partition {
823                    write!(f, " IN PARTITION {partition}")?;
824                }
825                Ok(())
826            }
827            AlterTableOperation::ClearProjection {
828                if_exists,
829                name,
830                partition,
831            } => {
832                write!(f, "CLEAR PROJECTION")?;
833                if *if_exists {
834                    write!(f, " IF EXISTS")?;
835                }
836                write!(f, " {name}")?;
837                if let Some(partition) = partition {
838                    write!(f, " IN PARTITION {partition}")?;
839                }
840                Ok(())
841            }
842            AlterTableOperation::AlterColumn { column_name, op } => {
843                write!(f, "ALTER COLUMN {column_name} {op}")
844            }
845            AlterTableOperation::DisableRowLevelSecurity => {
846                write!(f, "DISABLE ROW LEVEL SECURITY")
847            }
848            AlterTableOperation::DisableRule { name } => {
849                write!(f, "DISABLE RULE {name}")
850            }
851            AlterTableOperation::DisableTrigger { name } => {
852                write!(f, "DISABLE TRIGGER {name}")
853            }
854            AlterTableOperation::DropPartitions {
855                partitions,
856                if_exists,
857            } => write!(
858                f,
859                "DROP{ie} PARTITION ({})",
860                display_comma_separated(partitions),
861                ie = if *if_exists { " IF EXISTS" } else { "" }
862            ),
863            AlterTableOperation::DropConstraint {
864                if_exists,
865                name,
866                drop_behavior,
867            } => {
868                write!(
869                    f,
870                    "DROP CONSTRAINT {}{}",
871                    if *if_exists { "IF EXISTS " } else { "" },
872                    name
873                )?;
874                if let Some(drop_behavior) = drop_behavior {
875                    write!(f, " {drop_behavior}")?;
876                }
877                Ok(())
878            }
879            AlterTableOperation::DropPrimaryKey { drop_behavior } => {
880                write!(f, "DROP PRIMARY KEY")?;
881                if let Some(drop_behavior) = drop_behavior {
882                    write!(f, " {drop_behavior}")?;
883                }
884                Ok(())
885            }
886            AlterTableOperation::DropForeignKey {
887                name,
888                drop_behavior,
889            } => {
890                write!(f, "DROP FOREIGN KEY {name}")?;
891                if let Some(drop_behavior) = drop_behavior {
892                    write!(f, " {drop_behavior}")?;
893                }
894                Ok(())
895            }
896            AlterTableOperation::DropIndex { name } => write!(f, "DROP INDEX {name}"),
897            AlterTableOperation::DropColumn {
898                has_column_keyword,
899                column_names: column_name,
900                if_exists,
901                drop_behavior,
902            } => {
903                write!(
904                    f,
905                    "DROP {}{}{}",
906                    if *has_column_keyword { "COLUMN " } else { "" },
907                    if *if_exists { "IF EXISTS " } else { "" },
908                    display_comma_separated(column_name),
909                )?;
910                if let Some(drop_behavior) = drop_behavior {
911                    write!(f, " {drop_behavior}")?;
912                }
913                Ok(())
914            }
915            AlterTableOperation::AttachPartition { partition } => {
916                write!(f, "ATTACH {partition}")
917            }
918            AlterTableOperation::DetachPartition { partition } => {
919                write!(f, "DETACH {partition}")
920            }
921            AlterTableOperation::AttachPartitionOf {
922                partition_name,
923                partition_bound,
924            } => {
925                write!(f, "ATTACH PARTITION {partition_name} {partition_bound}")
926            }
927            AlterTableOperation::DetachPartitionOf {
928                partition_name,
929                concurrently,
930                finalize,
931            } => {
932                write!(f, "DETACH PARTITION {partition_name}")?;
933                if *concurrently {
934                    write!(f, " CONCURRENTLY")?;
935                }
936                if *finalize {
937                    write!(f, " FINALIZE")?;
938                }
939                Ok(())
940            }
941            AlterTableOperation::EnableAlwaysRule { name } => {
942                write!(f, "ENABLE ALWAYS RULE {name}")
943            }
944            AlterTableOperation::EnableAlwaysTrigger { name } => {
945                write!(f, "ENABLE ALWAYS TRIGGER {name}")
946            }
947            AlterTableOperation::EnableReplicaRule { name } => {
948                write!(f, "ENABLE REPLICA RULE {name}")
949            }
950            AlterTableOperation::EnableReplicaTrigger { name } => {
951                write!(f, "ENABLE REPLICA TRIGGER {name}")
952            }
953            AlterTableOperation::EnableRowLevelSecurity => {
954                write!(f, "ENABLE ROW LEVEL SECURITY")
955            }
956            AlterTableOperation::ForceRowLevelSecurity => {
957                write!(f, "FORCE ROW LEVEL SECURITY")
958            }
959            AlterTableOperation::NoForceRowLevelSecurity => {
960                write!(f, "NO FORCE ROW LEVEL SECURITY")
961            }
962            AlterTableOperation::EnableRule { name } => {
963                write!(f, "ENABLE RULE {name}")
964            }
965            AlterTableOperation::EnableTrigger { name } => {
966                write!(f, "ENABLE TRIGGER {name}")
967            }
968            AlterTableOperation::RenamePartitions {
969                old_partitions,
970                new_partitions,
971            } => write!(
972                f,
973                "PARTITION ({}) RENAME TO PARTITION ({})",
974                display_comma_separated(old_partitions),
975                display_comma_separated(new_partitions)
976            ),
977            AlterTableOperation::RenameColumn {
978                old_column_name,
979                new_column_name,
980            } => write!(f, "RENAME COLUMN {old_column_name} TO {new_column_name}"),
981            AlterTableOperation::RenameTable { table_name } => {
982                write!(f, "RENAME {table_name}")
983            }
984            AlterTableOperation::ChangeColumn {
985                old_name,
986                new_name,
987                data_type,
988                options,
989                column_position,
990            } => {
991                write!(f, "CHANGE COLUMN {old_name} {new_name} {data_type}")?;
992                if !options.is_empty() {
993                    write!(f, " {}", display_separated(options, " "))?;
994                }
995                if let Some(position) = column_position {
996                    write!(f, " {position}")?;
997                }
998
999                Ok(())
1000            }
1001            AlterTableOperation::ModifyColumn {
1002                col_name,
1003                data_type,
1004                options,
1005                column_position,
1006            } => {
1007                write!(f, "MODIFY COLUMN {col_name} {data_type}")?;
1008                if !options.is_empty() {
1009                    write!(f, " {}", display_separated(options, " "))?;
1010                }
1011                if let Some(position) = column_position {
1012                    write!(f, " {position}")?;
1013                }
1014
1015                Ok(())
1016            }
1017            AlterTableOperation::RenameConstraint { old_name, new_name } => {
1018                write!(f, "RENAME CONSTRAINT {old_name} TO {new_name}")
1019            }
1020            AlterTableOperation::SwapWith { table_name } => {
1021                write!(f, "SWAP WITH {table_name}")
1022            }
1023            AlterTableOperation::OwnerTo { new_owner } => {
1024                write!(f, "OWNER TO {new_owner}")
1025            }
1026            AlterTableOperation::SetTblProperties { table_properties } => {
1027                write!(
1028                    f,
1029                    "SET TBLPROPERTIES({})",
1030                    display_comma_separated(table_properties)
1031                )
1032            }
1033            AlterTableOperation::FreezePartition {
1034                partition,
1035                with_name,
1036            } => {
1037                write!(f, "FREEZE {partition}")?;
1038                if let Some(name) = with_name {
1039                    write!(f, " WITH NAME {name}")?;
1040                }
1041                Ok(())
1042            }
1043            AlterTableOperation::UnfreezePartition {
1044                partition,
1045                with_name,
1046            } => {
1047                write!(f, "UNFREEZE {partition}")?;
1048                if let Some(name) = with_name {
1049                    write!(f, " WITH NAME {name}")?;
1050                }
1051                Ok(())
1052            }
1053            AlterTableOperation::ClusterBy { exprs } => {
1054                write!(f, "CLUSTER BY ({})", display_comma_separated(exprs))?;
1055                Ok(())
1056            }
1057            AlterTableOperation::DropClusteringKey => {
1058                write!(f, "DROP CLUSTERING KEY")?;
1059                Ok(())
1060            }
1061            AlterTableOperation::AlterSortKey { columns } => {
1062                write!(f, "ALTER SORTKEY({})", display_comma_separated(columns))?;
1063                Ok(())
1064            }
1065            AlterTableOperation::SuspendRecluster => {
1066                write!(f, "SUSPEND RECLUSTER")?;
1067                Ok(())
1068            }
1069            AlterTableOperation::ResumeRecluster => {
1070                write!(f, "RESUME RECLUSTER")?;
1071                Ok(())
1072            }
1073            AlterTableOperation::Refresh { subpath } => {
1074                write!(f, "REFRESH")?;
1075                if let Some(path) = subpath {
1076                    write!(f, " '{path}'")?;
1077                }
1078                Ok(())
1079            }
1080            AlterTableOperation::Suspend => {
1081                write!(f, "SUSPEND")
1082            }
1083            AlterTableOperation::Resume => {
1084                write!(f, "RESUME")
1085            }
1086            AlterTableOperation::AutoIncrement { equals, value } => {
1087                write!(
1088                    f,
1089                    "AUTO_INCREMENT {}{}",
1090                    if *equals { "= " } else { "" },
1091                    value
1092                )
1093            }
1094            AlterTableOperation::Lock { equals, lock } => {
1095                write!(f, "LOCK {}{}", if *equals { "= " } else { "" }, lock)
1096            }
1097            AlterTableOperation::ReplicaIdentity { identity } => {
1098                write!(f, "REPLICA IDENTITY {identity}")
1099            }
1100            AlterTableOperation::ValidateConstraint { name } => {
1101                write!(f, "VALIDATE CONSTRAINT {name}")
1102            }
1103            AlterTableOperation::SetOptionsParens { options } => {
1104                write!(f, "SET ({})", display_comma_separated(options))
1105            }
1106            AlterTableOperation::SetTablespace { tablespace_name } => {
1107                write!(f, "SET TABLESPACE {tablespace_name}")
1108            }
1109        }
1110    }
1111}
1112
1113impl fmt::Display for AlterIndexOperation {
1114    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1115        match self {
1116            AlterIndexOperation::RenameIndex { index_name } => {
1117                write!(f, "RENAME TO {index_name}")
1118            }
1119            AlterIndexOperation::SetTablespace { tablespace_name } => {
1120                write!(f, "SET TABLESPACE {tablespace_name}")
1121            }
1122        }
1123    }
1124}
1125
1126/// An `ALTER TYPE` statement (`Statement::AlterType`)
1127#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1128#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1129#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1130pub struct AlterType {
1131    /// Name of the type being altered (may be schema-qualified).
1132    pub name: ObjectName,
1133    /// The specific alteration operation to perform.
1134    pub operation: AlterTypeOperation,
1135}
1136
1137/// An [AlterType] operation
1138#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1139#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1140#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1141pub enum AlterTypeOperation {
1142    /// Rename the type.
1143    Rename(AlterTypeRename),
1144    /// Add a new value to the type (for enum-like types).
1145    AddValue(AlterTypeAddValue),
1146    /// Rename an existing value of the type.
1147    RenameValue(AlterTypeRenameValue),
1148}
1149
1150/// See [AlterTypeOperation::Rename]
1151#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1152#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1153#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1154pub struct AlterTypeRename {
1155    /// The new name for the type.
1156    pub new_name: Ident,
1157}
1158
1159/// See [AlterTypeOperation::AddValue]
1160#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1161#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1162#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1163pub struct AlterTypeAddValue {
1164    /// If true, do not error when the value already exists (`IF NOT EXISTS`).
1165    pub if_not_exists: bool,
1166    /// The identifier for the new value to add.
1167    pub value: Ident,
1168    /// Optional relative position for the new value (`BEFORE` / `AFTER`).
1169    pub position: Option<AlterTypeAddValuePosition>,
1170}
1171
1172/// See [AlterTypeAddValue]
1173#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1174#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1175#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1176pub enum AlterTypeAddValuePosition {
1177    /// Place the new value before the given neighbor value.
1178    Before(Ident),
1179    /// Place the new value after the given neighbor value.
1180    After(Ident),
1181}
1182
1183/// See [AlterTypeOperation::RenameValue]
1184#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1185#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1186#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1187pub struct AlterTypeRenameValue {
1188    /// Existing value identifier to rename.
1189    pub from: Ident,
1190    /// New identifier for the value.
1191    pub to: Ident,
1192}
1193
1194impl fmt::Display for AlterTypeOperation {
1195    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1196        match self {
1197            Self::Rename(AlterTypeRename { new_name }) => {
1198                write!(f, "RENAME TO {new_name}")
1199            }
1200            Self::AddValue(AlterTypeAddValue {
1201                if_not_exists,
1202                value,
1203                position,
1204            }) => {
1205                write!(f, "ADD VALUE")?;
1206                if *if_not_exists {
1207                    write!(f, " IF NOT EXISTS")?;
1208                }
1209                write!(f, " {value}")?;
1210                match position {
1211                    Some(AlterTypeAddValuePosition::Before(neighbor_value)) => {
1212                        write!(f, " BEFORE {neighbor_value}")?;
1213                    }
1214                    Some(AlterTypeAddValuePosition::After(neighbor_value)) => {
1215                        write!(f, " AFTER {neighbor_value}")?;
1216                    }
1217                    None => {}
1218                };
1219                Ok(())
1220            }
1221            Self::RenameValue(AlterTypeRenameValue { from, to }) => {
1222                write!(f, "RENAME VALUE {from} TO {to}")
1223            }
1224        }
1225    }
1226}
1227
1228/// `ALTER OPERATOR` statement
1229/// See <https://www.postgresql.org/docs/current/sql-alteroperator.html>
1230#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1231#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1232#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1233pub struct AlterOperator {
1234    /// Operator name (can be schema-qualified)
1235    pub name: ObjectName,
1236    /// Left operand type (`None` if no left operand)
1237    pub left_type: Option<DataType>,
1238    /// Right operand type
1239    pub right_type: DataType,
1240    /// The operation to perform
1241    pub operation: AlterOperatorOperation,
1242}
1243
1244/// An [AlterOperator] operation
1245#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1246#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1247#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1248pub enum AlterOperatorOperation {
1249    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
1250    OwnerTo(Owner),
1251    /// `SET SCHEMA new_schema`
1252    /// Set the operator's schema name.
1253    SetSchema {
1254        /// New schema name for the operator
1255        schema_name: ObjectName,
1256    },
1257    /// `SET ( options )`
1258    Set {
1259        /// List of operator options to set
1260        options: Vec<OperatorOption>,
1261    },
1262}
1263
1264/// Option for `ALTER OPERATOR SET` operation
1265#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1266#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1267#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1268pub enum OperatorOption {
1269    /// `RESTRICT = { res_proc | NONE }`
1270    Restrict(Option<ObjectName>),
1271    /// `JOIN = { join_proc | NONE }`
1272    Join(Option<ObjectName>),
1273    /// `COMMUTATOR = com_op`
1274    Commutator(ObjectName),
1275    /// `NEGATOR = neg_op`
1276    Negator(ObjectName),
1277    /// `HASHES`
1278    Hashes,
1279    /// `MERGES`
1280    Merges,
1281}
1282
1283impl fmt::Display for AlterOperator {
1284    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1285        write!(f, "ALTER OPERATOR {} (", self.name)?;
1286        if let Some(left_type) = &self.left_type {
1287            write!(f, "{}", left_type)?;
1288        } else {
1289            write!(f, "NONE")?;
1290        }
1291        write!(f, ", {}) {}", self.right_type, self.operation)
1292    }
1293}
1294
1295impl fmt::Display for AlterOperatorOperation {
1296    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1297        match self {
1298            Self::OwnerTo(owner) => write!(f, "OWNER TO {}", owner),
1299            Self::SetSchema { schema_name } => write!(f, "SET SCHEMA {}", schema_name),
1300            Self::Set { options } => {
1301                write!(f, "SET (")?;
1302                for (i, option) in options.iter().enumerate() {
1303                    if i > 0 {
1304                        write!(f, ", ")?;
1305                    }
1306                    write!(f, "{}", option)?;
1307                }
1308                write!(f, ")")
1309            }
1310        }
1311    }
1312}
1313
1314impl fmt::Display for OperatorOption {
1315    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1316        match self {
1317            Self::Restrict(Some(proc_name)) => write!(f, "RESTRICT = {}", proc_name),
1318            Self::Restrict(None) => write!(f, "RESTRICT = NONE"),
1319            Self::Join(Some(proc_name)) => write!(f, "JOIN = {}", proc_name),
1320            Self::Join(None) => write!(f, "JOIN = NONE"),
1321            Self::Commutator(op_name) => write!(f, "COMMUTATOR = {}", op_name),
1322            Self::Negator(op_name) => write!(f, "NEGATOR = {}", op_name),
1323            Self::Hashes => write!(f, "HASHES"),
1324            Self::Merges => write!(f, "MERGES"),
1325        }
1326    }
1327}
1328
1329/// An `ALTER COLUMN` (`Statement::AlterTable`) operation
1330#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1331#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1332#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1333pub enum AlterColumnOperation {
1334    /// `SET NOT NULL`
1335    SetNotNull,
1336    /// `DROP NOT NULL`
1337    DropNotNull,
1338    /// `SET DEFAULT <expr>`
1339    /// Set the column default value.
1340    SetDefault {
1341        /// Expression representing the new default value.
1342        value: Expr,
1343    },
1344    /// `DROP DEFAULT`
1345    DropDefault,
1346    /// `[SET DATA] TYPE <data_type> [USING <expr>]`
1347    SetDataType {
1348        /// Target data type for the column.
1349        data_type: DataType,
1350        /// PostgreSQL-specific `USING <expr>` expression for conversion.
1351        using: Option<Expr>,
1352        /// Set to true if the statement includes the `SET DATA TYPE` keywords.
1353        had_set: bool,
1354    },
1355
1356    /// `ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]`
1357    ///
1358    /// Note: this is a PostgreSQL-specific operation.
1359    AddGenerated {
1360        /// Optional `GENERATED AS` specifier (e.g. `ALWAYS` or `BY DEFAULT`).
1361        generated_as: Option<GeneratedAs>,
1362        /// Optional sequence options for identity generation.
1363        sequence_options: Option<Vec<SequenceOptions>>,
1364    },
1365}
1366
1367impl fmt::Display for AlterColumnOperation {
1368    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1369        match self {
1370            AlterColumnOperation::SetNotNull => write!(f, "SET NOT NULL",),
1371            AlterColumnOperation::DropNotNull => write!(f, "DROP NOT NULL",),
1372            AlterColumnOperation::SetDefault { value } => {
1373                write!(f, "SET DEFAULT {value}")
1374            }
1375            AlterColumnOperation::DropDefault => {
1376                write!(f, "DROP DEFAULT")
1377            }
1378            AlterColumnOperation::SetDataType {
1379                data_type,
1380                using,
1381                had_set,
1382            } => {
1383                if *had_set {
1384                    write!(f, "SET DATA ")?;
1385                }
1386                write!(f, "TYPE {data_type}")?;
1387                if let Some(expr) = using {
1388                    write!(f, " USING {expr}")?;
1389                }
1390                Ok(())
1391            }
1392            AlterColumnOperation::AddGenerated {
1393                generated_as,
1394                sequence_options,
1395            } => {
1396                let generated_as = match generated_as {
1397                    Some(GeneratedAs::Always) => " ALWAYS",
1398                    Some(GeneratedAs::ByDefault) => " BY DEFAULT",
1399                    _ => "",
1400                };
1401
1402                write!(f, "ADD GENERATED{generated_as} AS IDENTITY",)?;
1403                if let Some(options) = sequence_options {
1404                    write!(f, " (")?;
1405
1406                    for sequence_option in options {
1407                        write!(f, "{sequence_option}")?;
1408                    }
1409
1410                    write!(f, " )")?;
1411                }
1412                Ok(())
1413            }
1414        }
1415    }
1416}
1417
1418/// Representation whether a definition can can contains the KEY or INDEX keywords with the same
1419/// meaning.
1420///
1421/// This enum initially is directed to `FULLTEXT`,`SPATIAL`, and `UNIQUE` indexes on create table
1422/// statements of `MySQL` [(1)].
1423///
1424/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1425#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1426#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1427#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1428pub enum KeyOrIndexDisplay {
1429    /// Nothing to display
1430    None,
1431    /// Display the KEY keyword
1432    Key,
1433    /// Display the INDEX keyword
1434    Index,
1435}
1436
1437impl KeyOrIndexDisplay {
1438    /// Check if this is the `None` variant.
1439    pub fn is_none(self) -> bool {
1440        matches!(self, Self::None)
1441    }
1442}
1443
1444impl fmt::Display for KeyOrIndexDisplay {
1445    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1446        let left_space = matches!(f.align(), Some(fmt::Alignment::Right));
1447
1448        if left_space && !self.is_none() {
1449            f.write_char(' ')?
1450        }
1451
1452        match self {
1453            KeyOrIndexDisplay::None => {
1454                write!(f, "")
1455            }
1456            KeyOrIndexDisplay::Key => {
1457                write!(f, "KEY")
1458            }
1459            KeyOrIndexDisplay::Index => {
1460                write!(f, "INDEX")
1461            }
1462        }
1463    }
1464}
1465
1466/// Indexing method used by that index.
1467///
1468/// This structure isn't present on ANSI, but is found at least in [`MySQL` CREATE TABLE][1],
1469/// [`MySQL` CREATE INDEX][2], and [Postgresql CREATE INDEX][3] statements.
1470///
1471/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1472/// [2]: https://dev.mysql.com/doc/refman/8.0/en/create-index.html
1473/// [3]: https://www.postgresql.org/docs/14/sql-createindex.html
1474#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1475#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1476#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1477pub enum IndexType {
1478    /// B-Tree index (commonly default for many databases).
1479    BTree,
1480    /// Hash index.
1481    Hash,
1482    /// Generalized Inverted Index (GIN).
1483    GIN,
1484    /// Generalized Search Tree (GiST) index.
1485    GiST,
1486    /// Space-partitioned GiST (SPGiST) index.
1487    SPGiST,
1488    /// Block Range Index (BRIN).
1489    BRIN,
1490    /// Bloom filter based index.
1491    Bloom,
1492    /// Users may define their own index types, which would
1493    /// not be covered by the above variants.
1494    Custom(Ident),
1495}
1496
1497impl fmt::Display for IndexType {
1498    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1499        match self {
1500            Self::BTree => write!(f, "BTREE"),
1501            Self::Hash => write!(f, "HASH"),
1502            Self::GIN => write!(f, "GIN"),
1503            Self::GiST => write!(f, "GIST"),
1504            Self::SPGiST => write!(f, "SPGIST"),
1505            Self::BRIN => write!(f, "BRIN"),
1506            Self::Bloom => write!(f, "BLOOM"),
1507            Self::Custom(name) => write!(f, "{name}"),
1508        }
1509    }
1510}
1511
1512/// MySQL index option, used in [`CREATE TABLE`], [`CREATE INDEX`], and [`ALTER TABLE`].
1513///
1514/// [`CREATE TABLE`]: https://dev.mysql.com/doc/refman/8.4/en/create-table.html
1515/// [`CREATE INDEX`]: https://dev.mysql.com/doc/refman/8.4/en/create-index.html
1516/// [`ALTER TABLE`]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
1517#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1518#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1519#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1520pub enum IndexOption {
1521    /// `USING { BTREE | HASH }`: Index type to use for the index.
1522    ///
1523    /// Note that we permissively parse non-MySQL index types, like `GIN`.
1524    Using(IndexType),
1525    /// `COMMENT 'string'`: Specifies a comment for the index.
1526    Comment(String),
1527}
1528
1529impl fmt::Display for IndexOption {
1530    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1531        match self {
1532            Self::Using(index_type) => write!(f, "USING {index_type}"),
1533            Self::Comment(s) => write!(f, "COMMENT '{s}'"),
1534        }
1535    }
1536}
1537
1538/// [PostgreSQL] unique index nulls handling option: `[ NULLS [ NOT ] DISTINCT ]`
1539///
1540/// [PostgreSQL]: https://www.postgresql.org/docs/17/sql-altertable.html
1541#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1542#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1543#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1544pub enum NullsDistinctOption {
1545    /// Not specified
1546    None,
1547    /// NULLS DISTINCT
1548    Distinct,
1549    /// NULLS NOT DISTINCT
1550    NotDistinct,
1551}
1552
1553impl fmt::Display for NullsDistinctOption {
1554    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1555        match self {
1556            Self::None => Ok(()),
1557            Self::Distinct => write!(f, " NULLS DISTINCT"),
1558            Self::NotDistinct => write!(f, " NULLS NOT DISTINCT"),
1559        }
1560    }
1561}
1562
1563#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1564#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1565#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1566/// A parameter of a stored procedure or function declaration.
1567pub struct ProcedureParam {
1568    /// Parameter name.
1569    pub name: Ident,
1570    /// Parameter data type.
1571    pub data_type: DataType,
1572    /// Optional mode (`IN`, `OUT`, `INOUT`, etc.).
1573    pub mode: Option<ArgMode>,
1574    /// Optional default expression for the parameter.
1575    pub default: Option<Expr>,
1576}
1577
1578impl fmt::Display for ProcedureParam {
1579    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1580        if let Some(mode) = &self.mode {
1581            if let Some(default) = &self.default {
1582                write!(f, "{mode} {} {} = {}", self.name, self.data_type, default)
1583            } else {
1584                write!(f, "{mode} {} {}", self.name, self.data_type)
1585            }
1586        } else if let Some(default) = &self.default {
1587            write!(f, "{} {} = {}", self.name, self.data_type, default)
1588        } else {
1589            write!(f, "{} {}", self.name, self.data_type)
1590        }
1591    }
1592}
1593
1594/// SQL column definition
1595#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1596#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1597#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1598pub struct ColumnDef {
1599    /// Column name.
1600    pub name: Ident,
1601    /// Column data type.
1602    pub data_type: DataType,
1603    /// Column options (defaults, constraints, generated, etc.).
1604    pub options: Vec<ColumnOptionDef>,
1605}
1606
1607impl fmt::Display for ColumnDef {
1608    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1609        if self.data_type == DataType::Unspecified {
1610            write!(f, "{}", self.name)?;
1611        } else {
1612            write!(f, "{} {}", self.name, self.data_type)?;
1613        }
1614        for option in &self.options {
1615            write!(f, " {option}")?;
1616        }
1617        Ok(())
1618    }
1619}
1620
1621/// Column definition specified in a `CREATE VIEW` statement.
1622///
1623/// Syntax
1624/// ```markdown
1625/// <name> [data_type][OPTIONS(option, ...)]
1626///
1627/// option: <name> = <value>
1628/// ```
1629///
1630/// Examples:
1631/// ```sql
1632/// name
1633/// age OPTIONS(description = "age column", tag = "prod")
1634/// amount COMMENT 'The total amount for the order line'
1635/// created_at DateTime64
1636/// ```
1637#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1638#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1639#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1640pub struct ViewColumnDef {
1641    /// Column identifier.
1642    pub name: Ident,
1643    /// Optional data type for the column.
1644    pub data_type: Option<DataType>,
1645    /// Optional column options (defaults, comments, etc.).
1646    pub options: Option<ColumnOptions>,
1647}
1648
1649#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1650#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1651#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1652/// Representation of how multiple `ColumnOption`s are grouped for a column.
1653pub enum ColumnOptions {
1654    /// Options separated by comma: `OPTIONS(a, b, c)`.
1655    CommaSeparated(Vec<ColumnOption>),
1656    /// Options separated by spaces: `OPTION_A OPTION_B`.
1657    SpaceSeparated(Vec<ColumnOption>),
1658}
1659
1660impl ColumnOptions {
1661    /// Get the column options as a slice.
1662    pub fn as_slice(&self) -> &[ColumnOption] {
1663        match self {
1664            ColumnOptions::CommaSeparated(options) => options.as_slice(),
1665            ColumnOptions::SpaceSeparated(options) => options.as_slice(),
1666        }
1667    }
1668}
1669
1670impl fmt::Display for ViewColumnDef {
1671    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1672        write!(f, "{}", self.name)?;
1673        if let Some(data_type) = self.data_type.as_ref() {
1674            write!(f, " {data_type}")?;
1675        }
1676        if let Some(options) = self.options.as_ref() {
1677            match options {
1678                ColumnOptions::CommaSeparated(column_options) => {
1679                    write!(f, " {}", display_comma_separated(column_options.as_slice()))?;
1680                }
1681                ColumnOptions::SpaceSeparated(column_options) => {
1682                    write!(f, " {}", display_separated(column_options.as_slice(), " "))?
1683                }
1684            }
1685        }
1686        Ok(())
1687    }
1688}
1689
1690/// An optionally-named `ColumnOption`: `[ CONSTRAINT <name> ] <column-option>`.
1691///
1692/// Note that implementations are substantially more permissive than the ANSI
1693/// specification on what order column options can be presented in, and whether
1694/// they are allowed to be named. The specification distinguishes between
1695/// constraints (NOT NULL, UNIQUE, PRIMARY KEY, and CHECK), which can be named
1696/// and can appear in any order, and other options (DEFAULT, GENERATED), which
1697/// cannot be named and must appear in a fixed order. `PostgreSQL`, however,
1698/// allows preceding any option with `CONSTRAINT <name>`, even those that are
1699/// not really constraints, like NULL and DEFAULT. MSSQL is less permissive,
1700/// allowing DEFAULT, UNIQUE, PRIMARY KEY and CHECK to be named, but not NULL or
1701/// NOT NULL constraints (the last of which is in violation of the spec).
1702///
1703/// For maximum flexibility, we don't distinguish between constraint and
1704/// non-constraint options, lumping them all together under the umbrella of
1705/// "column options," and we allow any column option to be named.
1706#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1707#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1708#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1709pub struct ColumnOptionDef {
1710    /// Optional name of the constraint.
1711    pub name: Option<Ident>,
1712    /// The actual column option (e.g. `NOT NULL`, `DEFAULT`, `GENERATED`, ...).
1713    pub option: ColumnOption,
1714}
1715
1716impl fmt::Display for ColumnOptionDef {
1717    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1718        write!(f, "{}{}", display_constraint_name(&self.name), self.option)
1719    }
1720}
1721
1722/// Identity is a column option for defining an identity or autoincrement column in a `CREATE TABLE` statement.
1723/// Syntax
1724/// ```sql
1725/// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1726/// ```
1727/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1728/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1729#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1730#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1731#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1732pub enum IdentityPropertyKind {
1733    /// An identity property declared via the `AUTOINCREMENT` key word
1734    /// Example:
1735    /// ```sql
1736    ///  AUTOINCREMENT(100, 1) NOORDER
1737    ///  AUTOINCREMENT START 100 INCREMENT 1 ORDER
1738    /// ```
1739    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1740    Autoincrement(IdentityProperty),
1741    /// An identity property declared via the `IDENTITY` key word
1742    /// Example, [MS SQL Server] or [Snowflake]:
1743    /// ```sql
1744    ///  IDENTITY(100, 1)
1745    /// ```
1746    /// [Snowflake]
1747    /// ```sql
1748    ///  IDENTITY(100, 1) ORDER
1749    ///  IDENTITY START 100 INCREMENT 1 NOORDER
1750    /// ```
1751    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1752    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1753    Identity(IdentityProperty),
1754}
1755
1756impl fmt::Display for IdentityPropertyKind {
1757    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1758        let (command, property) = match self {
1759            IdentityPropertyKind::Identity(property) => ("IDENTITY", property),
1760            IdentityPropertyKind::Autoincrement(property) => ("AUTOINCREMENT", property),
1761        };
1762        write!(f, "{command}")?;
1763        if let Some(parameters) = &property.parameters {
1764            write!(f, "{parameters}")?;
1765        }
1766        if let Some(order) = &property.order {
1767            write!(f, "{order}")?;
1768        }
1769        Ok(())
1770    }
1771}
1772
1773/// Properties for the `IDENTITY` / `AUTOINCREMENT` column option.
1774#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1775#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1776#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1777pub struct IdentityProperty {
1778    /// Optional parameters specifying seed/increment for the identity column.
1779    pub parameters: Option<IdentityPropertyFormatKind>,
1780    /// Optional ordering specifier (`ORDER` / `NOORDER`).
1781    pub order: Option<IdentityPropertyOrder>,
1782}
1783
1784/// A format of parameters of identity column.
1785///
1786/// It is [Snowflake] specific.
1787/// Syntax
1788/// ```sql
1789/// (seed , increment) | START num INCREMENT num
1790/// ```
1791/// [MS SQL Server] uses one way of representing these parameters.
1792/// Syntax
1793/// ```sql
1794/// (seed , increment)
1795/// ```
1796/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1797/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1798#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1799#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1800#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1801pub enum IdentityPropertyFormatKind {
1802    /// A parameters of identity column declared like parameters of function call
1803    /// Example:
1804    /// ```sql
1805    ///  (100, 1)
1806    /// ```
1807    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1808    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1809    FunctionCall(IdentityParameters),
1810    /// A parameters of identity column declared with keywords `START` and `INCREMENT`
1811    /// Example:
1812    /// ```sql
1813    ///  START 100 INCREMENT 1
1814    /// ```
1815    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1816    StartAndIncrement(IdentityParameters),
1817}
1818
1819impl fmt::Display for IdentityPropertyFormatKind {
1820    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1821        match self {
1822            IdentityPropertyFormatKind::FunctionCall(parameters) => {
1823                write!(f, "({}, {})", parameters.seed, parameters.increment)
1824            }
1825            IdentityPropertyFormatKind::StartAndIncrement(parameters) => {
1826                write!(
1827                    f,
1828                    " START {} INCREMENT {}",
1829                    parameters.seed, parameters.increment
1830                )
1831            }
1832        }
1833    }
1834}
1835/// Parameters specifying seed and increment for identity columns.
1836#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1837#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1838#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1839pub struct IdentityParameters {
1840    /// The initial seed expression for the identity column.
1841    pub seed: Expr,
1842    /// The increment expression for the identity column.
1843    pub increment: Expr,
1844}
1845
1846/// The identity column option specifies how values are generated for the auto-incremented column, either in increasing or decreasing order.
1847/// Syntax
1848/// ```sql
1849/// ORDER | NOORDER
1850/// ```
1851/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1852#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1853#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1854#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1855pub enum IdentityPropertyOrder {
1856    /// `ORDER` - preserve ordering for generated values (where supported).
1857    Order,
1858    /// `NOORDER` - do not enforce ordering for generated values.
1859    NoOrder,
1860}
1861
1862impl fmt::Display for IdentityPropertyOrder {
1863    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1864        match self {
1865            IdentityPropertyOrder::Order => write!(f, " ORDER"),
1866            IdentityPropertyOrder::NoOrder => write!(f, " NOORDER"),
1867        }
1868    }
1869}
1870
1871/// Column policy that identify a security policy of access to a column.
1872/// Syntax
1873/// ```sql
1874/// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1875/// [ WITH ] PROJECTION POLICY <policy_name>
1876/// ```
1877/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1878#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1879#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1880#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1881pub enum ColumnPolicy {
1882    /// `MASKING POLICY (<property>)`
1883    MaskingPolicy(ColumnPolicyProperty),
1884    /// `PROJECTION POLICY (<property>)`
1885    ProjectionPolicy(ColumnPolicyProperty),
1886}
1887
1888impl fmt::Display for ColumnPolicy {
1889    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1890        let (command, property) = match self {
1891            ColumnPolicy::MaskingPolicy(property) => ("MASKING POLICY", property),
1892            ColumnPolicy::ProjectionPolicy(property) => ("PROJECTION POLICY", property),
1893        };
1894        if property.with {
1895            write!(f, "WITH ")?;
1896        }
1897        write!(f, "{command} {}", property.policy_name)?;
1898        if let Some(using_columns) = &property.using_columns {
1899            write!(f, " USING ({})", display_comma_separated(using_columns))?;
1900        }
1901        Ok(())
1902    }
1903}
1904
1905#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1906#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1907#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1908/// Properties describing a column policy (masking or projection).
1909pub struct ColumnPolicyProperty {
1910    /// This flag indicates that the column policy option is declared using the `WITH` prefix.
1911    /// Example
1912    /// ```sql
1913    /// WITH PROJECTION POLICY sample_policy
1914    /// ```
1915    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1916    pub with: bool,
1917    /// The name of the policy to apply to the column.
1918    pub policy_name: ObjectName,
1919    /// Optional list of column identifiers referenced by the policy.
1920    pub using_columns: Option<Vec<Ident>>,
1921}
1922
1923/// Tags option of column
1924/// Syntax
1925/// ```sql
1926/// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1927/// ```
1928/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1929#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1930#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1931#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1932pub struct TagsColumnOption {
1933    /// This flag indicates that the tags option is declared using the `WITH` prefix.
1934    /// Example:
1935    /// ```sql
1936    /// WITH TAG (A = 'Tag A')
1937    /// ```
1938    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1939    pub with: bool,
1940    /// List of tags to attach to the column.
1941    pub tags: Vec<Tag>,
1942}
1943
1944impl fmt::Display for TagsColumnOption {
1945    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1946        if self.with {
1947            write!(f, "WITH ")?;
1948        }
1949        write!(f, "TAG ({})", display_comma_separated(&self.tags))?;
1950        Ok(())
1951    }
1952}
1953
1954/// `ColumnOption`s are modifiers that follow a column definition in a `CREATE
1955/// TABLE` statement.
1956#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1957#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1958#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1959pub enum ColumnOption {
1960    /// `NULL`
1961    Null,
1962    /// `NOT NULL`
1963    NotNull,
1964    /// `DEFAULT <restricted-expr>`
1965    Default(Expr),
1966
1967    /// `MATERIALIZE <expr>`
1968    /// Syntax: `b INT MATERIALIZE (a + 1)`
1969    ///
1970    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1971    Materialized(Expr),
1972    /// `EPHEMERAL [<expr>]`
1973    ///
1974    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1975    Ephemeral(Option<Expr>),
1976    /// `ALIAS <expr>`
1977    ///
1978    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1979    Alias(Expr),
1980
1981    /// `PRIMARY KEY [<constraint_characteristics>]`
1982    PrimaryKey(PrimaryKeyConstraint),
1983    /// `UNIQUE [<constraint_characteristics>]`
1984    Unique(UniqueConstraint),
1985    /// A referential integrity constraint (`REFERENCES <foreign_table> (<referred_columns>)
1986    /// [ MATCH { FULL | PARTIAL | SIMPLE } ]
1987    /// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
1988    ///   [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
1989    /// }
1990    /// [<constraint_characteristics>]
1991    /// `).
1992    ForeignKey(ForeignKeyConstraint),
1993    /// `CHECK (<expr>)`
1994    Check(CheckConstraint),
1995    /// Dialect-specific options, such as:
1996    /// - MySQL's `AUTO_INCREMENT` or SQLite's `AUTOINCREMENT`
1997    /// - ...
1998    DialectSpecific(Vec<Token>),
1999    /// `CHARACTER SET <name>` column option
2000    CharacterSet(ObjectName),
2001    /// `COLLATE <name>` column option
2002    Collation(ObjectName),
2003    /// `COMMENT '<text>'` column option
2004    Comment(String),
2005    /// `ON UPDATE <expr>` column option
2006    OnUpdate(Expr),
2007    /// `Generated`s are modifiers that follow a column definition in a `CREATE
2008    /// TABLE` statement.
2009    Generated {
2010        /// How the column is generated (e.g. `GENERATED ALWAYS`, `BY DEFAULT`, or expression-stored).
2011        generated_as: GeneratedAs,
2012        /// Sequence/identity options when generation is backed by a sequence.
2013        sequence_options: Option<Vec<SequenceOptions>>,
2014        /// Optional expression used to generate the column value.
2015        generation_expr: Option<Expr>,
2016        /// Mode of the generated expression (`VIRTUAL` or `STORED`) when `generation_expr` is present.
2017        generation_expr_mode: Option<GeneratedExpressionMode>,
2018        /// false if 'GENERATED ALWAYS' is skipped (option starts with AS)
2019        generated_keyword: bool,
2020    },
2021    /// BigQuery specific: Explicit column options in a view [1] or table [2]
2022    /// Syntax
2023    /// ```sql
2024    /// OPTIONS(description="field desc")
2025    /// ```
2026    /// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#view_column_option_list
2027    /// [2]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#column_option_list
2028    Options(Vec<SqlOption>),
2029    /// Creates an identity or an autoincrement column in a table.
2030    /// Syntax
2031    /// ```sql
2032    /// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
2033    /// ```
2034    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
2035    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
2036    Identity(IdentityPropertyKind),
2037    /// SQLite specific: ON CONFLICT option on column definition
2038    /// <https://www.sqlite.org/lang_conflict.html>
2039    OnConflict(Keyword),
2040    /// Snowflake specific: an option of specifying security masking or projection policy to set on a column.
2041    /// Syntax:
2042    /// ```sql
2043    /// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
2044    /// [ WITH ] PROJECTION POLICY <policy_name>
2045    /// ```
2046    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
2047    Policy(ColumnPolicy),
2048    /// Snowflake specific: Specifies the tag name and the tag string value.
2049    /// Syntax:
2050    /// ```sql
2051    /// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
2052    /// ```
2053    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
2054    Tags(TagsColumnOption),
2055    /// MySQL specific: Spatial reference identifier
2056    /// Syntax:
2057    /// ```sql
2058    /// CREATE TABLE geom (g GEOMETRY NOT NULL SRID 4326);
2059    /// ```
2060    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/creating-spatial-indexes.html
2061    Srid(Box<Expr>),
2062    /// MySQL specific: Column is invisible via SELECT *
2063    /// Syntax:
2064    /// ```sql
2065    /// CREATE TABLE t (foo INT, bar INT INVISIBLE);
2066    /// ```
2067    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/invisible-columns.html
2068    Invisible,
2069}
2070
2071impl From<UniqueConstraint> for ColumnOption {
2072    fn from(c: UniqueConstraint) -> Self {
2073        ColumnOption::Unique(c)
2074    }
2075}
2076
2077impl From<PrimaryKeyConstraint> for ColumnOption {
2078    fn from(c: PrimaryKeyConstraint) -> Self {
2079        ColumnOption::PrimaryKey(c)
2080    }
2081}
2082
2083impl From<CheckConstraint> for ColumnOption {
2084    fn from(c: CheckConstraint) -> Self {
2085        ColumnOption::Check(c)
2086    }
2087}
2088impl From<ForeignKeyConstraint> for ColumnOption {
2089    fn from(fk: ForeignKeyConstraint) -> Self {
2090        ColumnOption::ForeignKey(fk)
2091    }
2092}
2093
2094impl fmt::Display for ColumnOption {
2095    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2096        use ColumnOption::*;
2097        match self {
2098            Null => write!(f, "NULL"),
2099            NotNull => write!(f, "NOT NULL"),
2100            Default(expr) => write!(f, "DEFAULT {expr}"),
2101            Materialized(expr) => write!(f, "MATERIALIZED {expr}"),
2102            Ephemeral(expr) => {
2103                if let Some(e) = expr {
2104                    write!(f, "EPHEMERAL {e}")
2105                } else {
2106                    write!(f, "EPHEMERAL")
2107                }
2108            }
2109            Alias(expr) => write!(f, "ALIAS {expr}"),
2110            PrimaryKey(constraint) => {
2111                write!(f, "PRIMARY KEY")?;
2112                if let Some(characteristics) = &constraint.characteristics {
2113                    write!(f, " {characteristics}")?;
2114                }
2115                Ok(())
2116            }
2117            Unique(constraint) => {
2118                write!(f, "UNIQUE{:>}", constraint.index_type_display)?;
2119                if let Some(characteristics) = &constraint.characteristics {
2120                    write!(f, " {characteristics}")?;
2121                }
2122                Ok(())
2123            }
2124            ForeignKey(constraint) => {
2125                write!(f, "REFERENCES {}", constraint.foreign_table)?;
2126                if !constraint.referred_columns.is_empty() {
2127                    write!(
2128                        f,
2129                        " ({})",
2130                        display_comma_separated(&constraint.referred_columns)
2131                    )?;
2132                }
2133                if let Some(match_kind) = &constraint.match_kind {
2134                    write!(f, " {match_kind}")?;
2135                }
2136                if let Some(action) = &constraint.on_delete {
2137                    write!(f, " ON DELETE {action}")?;
2138                }
2139                if let Some(action) = &constraint.on_update {
2140                    write!(f, " ON UPDATE {action}")?;
2141                }
2142                if let Some(characteristics) = &constraint.characteristics {
2143                    write!(f, " {characteristics}")?;
2144                }
2145                Ok(())
2146            }
2147            Check(constraint) => write!(f, "{constraint}"),
2148            DialectSpecific(val) => write!(f, "{}", display_separated(val, " ")),
2149            CharacterSet(n) => write!(f, "CHARACTER SET {n}"),
2150            Collation(n) => write!(f, "COLLATE {n}"),
2151            Comment(v) => write!(f, "COMMENT '{}'", escape_single_quote_string(v)),
2152            OnUpdate(expr) => write!(f, "ON UPDATE {expr}"),
2153            Generated {
2154                generated_as,
2155                sequence_options,
2156                generation_expr,
2157                generation_expr_mode,
2158                generated_keyword,
2159            } => {
2160                if let Some(expr) = generation_expr {
2161                    let modifier = match generation_expr_mode {
2162                        None => "",
2163                        Some(GeneratedExpressionMode::Virtual) => " VIRTUAL",
2164                        Some(GeneratedExpressionMode::Stored) => " STORED",
2165                    };
2166                    if *generated_keyword {
2167                        write!(f, "GENERATED ALWAYS AS ({expr}){modifier}")?;
2168                    } else {
2169                        write!(f, "AS ({expr}){modifier}")?;
2170                    }
2171                    Ok(())
2172                } else {
2173                    // Like Postgres - generated from sequence
2174                    let when = match generated_as {
2175                        GeneratedAs::Always => "ALWAYS",
2176                        GeneratedAs::ByDefault => "BY DEFAULT",
2177                        // ExpStored goes with an expression, handled above
2178                        GeneratedAs::ExpStored => "",
2179                    };
2180                    write!(f, "GENERATED {when} AS IDENTITY")?;
2181                    if sequence_options.is_some() {
2182                        let so = sequence_options.as_ref().unwrap();
2183                        if !so.is_empty() {
2184                            write!(f, " (")?;
2185                        }
2186                        for sequence_option in so {
2187                            write!(f, "{sequence_option}")?;
2188                        }
2189                        if !so.is_empty() {
2190                            write!(f, " )")?;
2191                        }
2192                    }
2193                    Ok(())
2194                }
2195            }
2196            Options(options) => {
2197                write!(f, "OPTIONS({})", display_comma_separated(options))
2198            }
2199            Identity(parameters) => {
2200                write!(f, "{parameters}")
2201            }
2202            OnConflict(keyword) => {
2203                write!(f, "ON CONFLICT {keyword:?}")?;
2204                Ok(())
2205            }
2206            Policy(parameters) => {
2207                write!(f, "{parameters}")
2208            }
2209            Tags(tags) => {
2210                write!(f, "{tags}")
2211            }
2212            Srid(srid) => {
2213                write!(f, "SRID {srid}")
2214            }
2215            Invisible => {
2216                write!(f, "INVISIBLE")
2217            }
2218        }
2219    }
2220}
2221
2222/// `GeneratedAs`s are modifiers that follow a column option in a `generated`.
2223/// 'ExpStored' is used for a column generated from an expression and stored.
2224#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
2225#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2226#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2227pub enum GeneratedAs {
2228    /// `GENERATED ALWAYS`
2229    Always,
2230    /// `GENERATED BY DEFAULT`
2231    ByDefault,
2232    /// Expression-based generated column that is stored (used internally for expression-stored columns)
2233    ExpStored,
2234}
2235
2236/// `GeneratedExpressionMode`s are modifiers that follow an expression in a `generated`.
2237/// No modifier is typically the same as Virtual.
2238#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
2239#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2240#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2241pub enum GeneratedExpressionMode {
2242    /// `VIRTUAL` generated expression
2243    Virtual,
2244    /// `STORED` generated expression
2245    Stored,
2246}
2247
2248#[must_use]
2249pub(crate) fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
2250    struct ConstraintName<'a>(&'a Option<Ident>);
2251    impl fmt::Display for ConstraintName<'_> {
2252        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2253            if let Some(name) = self.0 {
2254                write!(f, "CONSTRAINT {name} ")?;
2255            }
2256            Ok(())
2257        }
2258    }
2259    ConstraintName(name)
2260}
2261
2262/// If `option` is
2263/// * `Some(inner)` => create display struct for `"{prefix}{inner}{postfix}"`
2264/// * `_` => do nothing
2265#[must_use]
2266pub(crate) fn display_option<'a, T: fmt::Display>(
2267    prefix: &'a str,
2268    postfix: &'a str,
2269    option: &'a Option<T>,
2270) -> impl fmt::Display + 'a {
2271    struct OptionDisplay<'a, T>(&'a str, &'a str, &'a Option<T>);
2272    impl<T: fmt::Display> fmt::Display for OptionDisplay<'_, T> {
2273        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2274            if let Some(inner) = self.2 {
2275                let (prefix, postfix) = (self.0, self.1);
2276                write!(f, "{prefix}{inner}{postfix}")?;
2277            }
2278            Ok(())
2279        }
2280    }
2281    OptionDisplay(prefix, postfix, option)
2282}
2283
2284/// If `option` is
2285/// * `Some(inner)` => create display struct for `" {inner}"`
2286/// * `_` => do nothing
2287#[must_use]
2288pub(crate) fn display_option_spaced<T: fmt::Display>(option: &Option<T>) -> impl fmt::Display + '_ {
2289    display_option(" ", "", option)
2290}
2291
2292/// `<constraint_characteristics> = [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ]`
2293///
2294/// Used in UNIQUE and foreign key constraints. The individual settings may occur in any order.
2295#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Default, Eq, Ord, Hash)]
2296#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2297#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2298pub struct ConstraintCharacteristics {
2299    /// `[ DEFERRABLE | NOT DEFERRABLE ]`
2300    pub deferrable: Option<bool>,
2301    /// `[ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]`
2302    pub initially: Option<DeferrableInitial>,
2303    /// `[ ENFORCED | NOT ENFORCED ]`
2304    pub enforced: Option<bool>,
2305}
2306
2307/// Initial setting for deferrable constraints (`INITIALLY IMMEDIATE` or `INITIALLY DEFERRED`).
2308#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2309#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2310#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2311pub enum DeferrableInitial {
2312    /// `INITIALLY IMMEDIATE`
2313    Immediate,
2314    /// `INITIALLY DEFERRED`
2315    Deferred,
2316}
2317
2318impl ConstraintCharacteristics {
2319    fn deferrable_text(&self) -> Option<&'static str> {
2320        self.deferrable.map(|deferrable| {
2321            if deferrable {
2322                "DEFERRABLE"
2323            } else {
2324                "NOT DEFERRABLE"
2325            }
2326        })
2327    }
2328
2329    fn initially_immediate_text(&self) -> Option<&'static str> {
2330        self.initially
2331            .map(|initially_immediate| match initially_immediate {
2332                DeferrableInitial::Immediate => "INITIALLY IMMEDIATE",
2333                DeferrableInitial::Deferred => "INITIALLY DEFERRED",
2334            })
2335    }
2336
2337    fn enforced_text(&self) -> Option<&'static str> {
2338        self.enforced.map(
2339            |enforced| {
2340                if enforced {
2341                    "ENFORCED"
2342                } else {
2343                    "NOT ENFORCED"
2344                }
2345            },
2346        )
2347    }
2348}
2349
2350impl fmt::Display for ConstraintCharacteristics {
2351    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2352        let deferrable = self.deferrable_text();
2353        let initially_immediate = self.initially_immediate_text();
2354        let enforced = self.enforced_text();
2355
2356        match (deferrable, initially_immediate, enforced) {
2357            (None, None, None) => Ok(()),
2358            (None, None, Some(enforced)) => write!(f, "{enforced}"),
2359            (None, Some(initial), None) => write!(f, "{initial}"),
2360            (None, Some(initial), Some(enforced)) => write!(f, "{initial} {enforced}"),
2361            (Some(deferrable), None, None) => write!(f, "{deferrable}"),
2362            (Some(deferrable), None, Some(enforced)) => write!(f, "{deferrable} {enforced}"),
2363            (Some(deferrable), Some(initial), None) => write!(f, "{deferrable} {initial}"),
2364            (Some(deferrable), Some(initial), Some(enforced)) => {
2365                write!(f, "{deferrable} {initial} {enforced}")
2366            }
2367        }
2368    }
2369}
2370
2371/// `<referential_action> =
2372/// { RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT }`
2373///
2374/// Used in foreign key constraints in `ON UPDATE` and `ON DELETE` options.
2375#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2376#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2377#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2378pub enum ReferentialAction {
2379    /// `RESTRICT` - disallow action if it would break referential integrity.
2380    Restrict,
2381    /// `CASCADE` - propagate the action to referencing rows.
2382    Cascade,
2383    /// `SET NULL` - set referencing columns to NULL.
2384    SetNull,
2385    /// `NO ACTION` - no action at the time; may be deferred.
2386    NoAction,
2387    /// `SET DEFAULT` - set referencing columns to their default values.
2388    SetDefault,
2389}
2390
2391impl fmt::Display for ReferentialAction {
2392    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2393        f.write_str(match self {
2394            ReferentialAction::Restrict => "RESTRICT",
2395            ReferentialAction::Cascade => "CASCADE",
2396            ReferentialAction::SetNull => "SET NULL",
2397            ReferentialAction::NoAction => "NO ACTION",
2398            ReferentialAction::SetDefault => "SET DEFAULT",
2399        })
2400    }
2401}
2402
2403/// `<drop behavior> ::= CASCADE | RESTRICT`.
2404///
2405/// Used in `DROP` statements.
2406#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2407#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2408#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2409pub enum DropBehavior {
2410    /// `RESTRICT` - refuse to drop if there are any dependent objects.
2411    Restrict,
2412    /// `CASCADE` - automatically drop objects that depend on the object being dropped.
2413    Cascade,
2414}
2415
2416impl fmt::Display for DropBehavior {
2417    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2418        f.write_str(match self {
2419            DropBehavior::Restrict => "RESTRICT",
2420            DropBehavior::Cascade => "CASCADE",
2421        })
2422    }
2423}
2424
2425/// SQL user defined type definition
2426#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2427#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2428#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2429pub enum UserDefinedTypeRepresentation {
2430    /// Composite type: `CREATE TYPE name AS (attributes)`
2431    Composite {
2432        /// List of attributes for the composite type.
2433        attributes: Vec<UserDefinedTypeCompositeAttributeDef>,
2434    },
2435    /// Enum type: `CREATE TYPE name AS ENUM (labels)`
2436    ///
2437    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2438    /// Enum type: `CREATE TYPE name AS ENUM (labels)`
2439    Enum {
2440        /// Labels that make up the enum type.
2441        labels: Vec<Ident>,
2442    },
2443    /// Range type: `CREATE TYPE name AS RANGE (options)`
2444    ///
2445    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2446    Range {
2447        /// Options for the range type definition.
2448        options: Vec<UserDefinedTypeRangeOption>,
2449    },
2450    /// Base type (SQL definition): `CREATE TYPE name (options)`
2451    ///
2452    /// Note the lack of `AS` keyword
2453    ///
2454    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2455    SqlDefinition {
2456        /// Options for SQL definition of the user-defined type.
2457        options: Vec<UserDefinedTypeSqlDefinitionOption>,
2458    },
2459}
2460
2461impl fmt::Display for UserDefinedTypeRepresentation {
2462    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2463        match self {
2464            Self::Composite { attributes } => {
2465                write!(f, "AS ({})", display_comma_separated(attributes))
2466            }
2467            Self::Enum { labels } => {
2468                write!(f, "AS ENUM ({})", display_comma_separated(labels))
2469            }
2470            Self::Range { options } => {
2471                write!(f, "AS RANGE ({})", display_comma_separated(options))
2472            }
2473            Self::SqlDefinition { options } => {
2474                write!(f, "({})", display_comma_separated(options))
2475            }
2476        }
2477    }
2478}
2479
2480/// SQL user defined type attribute definition
2481#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2482#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2483#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2484pub struct UserDefinedTypeCompositeAttributeDef {
2485    /// Attribute name.
2486    pub name: Ident,
2487    /// Attribute data type.
2488    pub data_type: DataType,
2489    /// Optional collation for the attribute.
2490    pub collation: Option<ObjectName>,
2491}
2492
2493impl fmt::Display for UserDefinedTypeCompositeAttributeDef {
2494    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2495        write!(f, "{} {}", self.name, self.data_type)?;
2496        if let Some(collation) = &self.collation {
2497            write!(f, " COLLATE {collation}")?;
2498        }
2499        Ok(())
2500    }
2501}
2502
2503/// Internal length specification for PostgreSQL user-defined base types.
2504///
2505/// Specifies the internal length in bytes of the new type's internal representation.
2506/// The default assumption is that it is variable-length.
2507///
2508/// # PostgreSQL Documentation
2509/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2510///
2511/// # Examples
2512/// ```sql
2513/// CREATE TYPE mytype (
2514///     INPUT = in_func,
2515///     OUTPUT = out_func,
2516///     INTERNALLENGTH = 16  -- Fixed 16-byte length
2517/// );
2518///
2519/// CREATE TYPE mytype2 (
2520///     INPUT = in_func,
2521///     OUTPUT = out_func,
2522///     INTERNALLENGTH = VARIABLE  -- Variable length
2523/// );
2524/// ```
2525#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2526#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2527#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2528pub enum UserDefinedTypeInternalLength {
2529    /// Fixed internal length: `INTERNALLENGTH = <number>`
2530    Fixed(u64),
2531    /// Variable internal length: `INTERNALLENGTH = VARIABLE`
2532    Variable,
2533}
2534
2535impl fmt::Display for UserDefinedTypeInternalLength {
2536    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2537        match self {
2538            UserDefinedTypeInternalLength::Fixed(n) => write!(f, "{}", n),
2539            UserDefinedTypeInternalLength::Variable => write!(f, "VARIABLE"),
2540        }
2541    }
2542}
2543
2544/// Alignment specification for PostgreSQL user-defined base types.
2545///
2546/// Specifies the storage alignment requirement for values of the data type.
2547/// The allowed values equate to alignment on 1, 2, 4, or 8 byte boundaries.
2548/// Note that variable-length types must have an alignment of at least 4, since
2549/// they necessarily contain an int4 as their first component.
2550///
2551/// # PostgreSQL Documentation
2552/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2553///
2554/// # Examples
2555/// ```sql
2556/// CREATE TYPE mytype (
2557///     INPUT = in_func,
2558///     OUTPUT = out_func,
2559///     ALIGNMENT = int4  -- 4-byte alignment
2560/// );
2561/// ```
2562#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2563#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2564#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2565pub enum Alignment {
2566    /// Single-byte alignment: `ALIGNMENT = char`
2567    Char,
2568    /// 2-byte alignment: `ALIGNMENT = int2`
2569    Int2,
2570    /// 4-byte alignment: `ALIGNMENT = int4`
2571    Int4,
2572    /// 8-byte alignment: `ALIGNMENT = double`
2573    Double,
2574}
2575
2576impl fmt::Display for Alignment {
2577    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2578        match self {
2579            Alignment::Char => write!(f, "char"),
2580            Alignment::Int2 => write!(f, "int2"),
2581            Alignment::Int4 => write!(f, "int4"),
2582            Alignment::Double => write!(f, "double"),
2583        }
2584    }
2585}
2586
2587/// Storage specification for PostgreSQL user-defined base types.
2588///
2589/// Specifies the storage strategy for values of the data type:
2590/// - `plain`: Prevents compression and out-of-line storage (for fixed-length types)
2591/// - `external`: Allows out-of-line storage but not compression
2592/// - `extended`: Allows both compression and out-of-line storage (default for most types)
2593/// - `main`: Allows compression but discourages out-of-line storage
2594///
2595/// # PostgreSQL Documentation
2596/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2597///
2598/// # Examples
2599/// ```sql
2600/// CREATE TYPE mytype (
2601///     INPUT = in_func,
2602///     OUTPUT = out_func,
2603///     STORAGE = plain
2604/// );
2605/// ```
2606#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2607#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2608#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2609pub enum UserDefinedTypeStorage {
2610    /// No compression or out-of-line storage: `STORAGE = plain`
2611    Plain,
2612    /// Out-of-line storage allowed, no compression: `STORAGE = external`
2613    External,
2614    /// Both compression and out-of-line storage allowed: `STORAGE = extended`
2615    Extended,
2616    /// Compression allowed, out-of-line discouraged: `STORAGE = main`
2617    Main,
2618}
2619
2620impl fmt::Display for UserDefinedTypeStorage {
2621    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2622        match self {
2623            UserDefinedTypeStorage::Plain => write!(f, "plain"),
2624            UserDefinedTypeStorage::External => write!(f, "external"),
2625            UserDefinedTypeStorage::Extended => write!(f, "extended"),
2626            UserDefinedTypeStorage::Main => write!(f, "main"),
2627        }
2628    }
2629}
2630
2631/// Options for PostgreSQL `CREATE TYPE ... AS RANGE` statement.
2632///
2633/// Range types are data types representing a range of values of some element type
2634/// (called the range's subtype). These options configure the behavior of the range type.
2635///
2636/// # PostgreSQL Documentation
2637/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2638///
2639/// # Examples
2640/// ```sql
2641/// CREATE TYPE int4range AS RANGE (
2642///     SUBTYPE = int4,
2643///     SUBTYPE_OPCLASS = int4_ops,
2644///     CANONICAL = int4range_canonical,
2645///     SUBTYPE_DIFF = int4range_subdiff
2646/// );
2647/// ```
2648#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2649#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2650#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2651pub enum UserDefinedTypeRangeOption {
2652    /// The element type that the range type will represent: `SUBTYPE = subtype`
2653    Subtype(DataType),
2654    /// The operator class for the subtype: `SUBTYPE_OPCLASS = subtype_operator_class`
2655    SubtypeOpClass(ObjectName),
2656    /// Collation to use for ordering the subtype: `COLLATION = collation`
2657    Collation(ObjectName),
2658    /// Function to convert range values to canonical form: `CANONICAL = canonical_function`
2659    Canonical(ObjectName),
2660    /// Function to compute the difference between two subtype values: `SUBTYPE_DIFF = subtype_diff_function`
2661    SubtypeDiff(ObjectName),
2662    /// Name of the corresponding multirange type: `MULTIRANGE_TYPE_NAME = multirange_type_name`
2663    MultirangeTypeName(ObjectName),
2664}
2665
2666impl fmt::Display for UserDefinedTypeRangeOption {
2667    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2668        match self {
2669            UserDefinedTypeRangeOption::Subtype(dt) => write!(f, "SUBTYPE = {}", dt),
2670            UserDefinedTypeRangeOption::SubtypeOpClass(name) => {
2671                write!(f, "SUBTYPE_OPCLASS = {}", name)
2672            }
2673            UserDefinedTypeRangeOption::Collation(name) => write!(f, "COLLATION = {}", name),
2674            UserDefinedTypeRangeOption::Canonical(name) => write!(f, "CANONICAL = {}", name),
2675            UserDefinedTypeRangeOption::SubtypeDiff(name) => write!(f, "SUBTYPE_DIFF = {}", name),
2676            UserDefinedTypeRangeOption::MultirangeTypeName(name) => {
2677                write!(f, "MULTIRANGE_TYPE_NAME = {}", name)
2678            }
2679        }
2680    }
2681}
2682
2683/// Options for PostgreSQL `CREATE TYPE ... (<options>)` statement (base type definition).
2684///
2685/// Base types are the lowest-level data types in PostgreSQL. To define a new base type,
2686/// you must specify functions that convert it to and from text representation, and optionally
2687/// binary representation and other properties.
2688///
2689/// Note: This syntax uses parentheses directly after the type name, without the `AS` keyword.
2690///
2691/// # PostgreSQL Documentation
2692/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2693///
2694/// # Examples
2695/// ```sql
2696/// CREATE TYPE complex (
2697///     INPUT = complex_in,
2698///     OUTPUT = complex_out,
2699///     INTERNALLENGTH = 16,
2700///     ALIGNMENT = double
2701/// );
2702/// ```
2703#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2704#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2705#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2706pub enum UserDefinedTypeSqlDefinitionOption {
2707    /// Function to convert from external text representation to internal: `INPUT = input_function`
2708    Input(ObjectName),
2709    /// Function to convert from internal to external text representation: `OUTPUT = output_function`
2710    Output(ObjectName),
2711    /// Function to convert from external binary representation to internal: `RECEIVE = receive_function`
2712    Receive(ObjectName),
2713    /// Function to convert from internal to external binary representation: `SEND = send_function`
2714    Send(ObjectName),
2715    /// Function to convert type modifiers from text array to internal form: `TYPMOD_IN = type_modifier_input_function`
2716    TypmodIn(ObjectName),
2717    /// Function to convert type modifiers from internal to text form: `TYPMOD_OUT = type_modifier_output_function`
2718    TypmodOut(ObjectName),
2719    /// Function to compute statistics for the data type: `ANALYZE = analyze_function`
2720    Analyze(ObjectName),
2721    /// Function to handle subscripting operations: `SUBSCRIPT = subscript_function`
2722    Subscript(ObjectName),
2723    /// Internal storage size in bytes, or VARIABLE for variable-length: `INTERNALLENGTH = { internallength | VARIABLE }`
2724    InternalLength(UserDefinedTypeInternalLength),
2725    /// Indicates values are passed by value rather than by reference: `PASSEDBYVALUE`
2726    PassedByValue,
2727    /// Storage alignment requirement (1, 2, 4, or 8 bytes): `ALIGNMENT = alignment`
2728    Alignment(Alignment),
2729    /// Storage strategy for varlena types: `STORAGE = storage`
2730    Storage(UserDefinedTypeStorage),
2731    /// Copy properties from an existing type: `LIKE = like_type`
2732    Like(ObjectName),
2733    /// Type category for implicit casting rules (single char): `CATEGORY = category`
2734    Category(char),
2735    /// Whether this type is preferred within its category: `PREFERRED = preferred`
2736    Preferred(bool),
2737    /// Default value for the type: `DEFAULT = default`
2738    Default(Expr),
2739    /// Element type for array types: `ELEMENT = element`
2740    Element(DataType),
2741    /// Delimiter character for array value display: `DELIMITER = delimiter`
2742    Delimiter(String),
2743    /// Whether the type supports collation: `COLLATABLE = collatable`
2744    Collatable(bool),
2745}
2746
2747impl fmt::Display for UserDefinedTypeSqlDefinitionOption {
2748    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2749        match self {
2750            UserDefinedTypeSqlDefinitionOption::Input(name) => write!(f, "INPUT = {}", name),
2751            UserDefinedTypeSqlDefinitionOption::Output(name) => write!(f, "OUTPUT = {}", name),
2752            UserDefinedTypeSqlDefinitionOption::Receive(name) => write!(f, "RECEIVE = {}", name),
2753            UserDefinedTypeSqlDefinitionOption::Send(name) => write!(f, "SEND = {}", name),
2754            UserDefinedTypeSqlDefinitionOption::TypmodIn(name) => write!(f, "TYPMOD_IN = {}", name),
2755            UserDefinedTypeSqlDefinitionOption::TypmodOut(name) => {
2756                write!(f, "TYPMOD_OUT = {}", name)
2757            }
2758            UserDefinedTypeSqlDefinitionOption::Analyze(name) => write!(f, "ANALYZE = {}", name),
2759            UserDefinedTypeSqlDefinitionOption::Subscript(name) => {
2760                write!(f, "SUBSCRIPT = {}", name)
2761            }
2762            UserDefinedTypeSqlDefinitionOption::InternalLength(len) => {
2763                write!(f, "INTERNALLENGTH = {}", len)
2764            }
2765            UserDefinedTypeSqlDefinitionOption::PassedByValue => write!(f, "PASSEDBYVALUE"),
2766            UserDefinedTypeSqlDefinitionOption::Alignment(align) => {
2767                write!(f, "ALIGNMENT = {}", align)
2768            }
2769            UserDefinedTypeSqlDefinitionOption::Storage(storage) => {
2770                write!(f, "STORAGE = {}", storage)
2771            }
2772            UserDefinedTypeSqlDefinitionOption::Like(name) => write!(f, "LIKE = {}", name),
2773            UserDefinedTypeSqlDefinitionOption::Category(c) => write!(f, "CATEGORY = '{}'", c),
2774            UserDefinedTypeSqlDefinitionOption::Preferred(b) => write!(f, "PREFERRED = {}", b),
2775            UserDefinedTypeSqlDefinitionOption::Default(expr) => write!(f, "DEFAULT = {}", expr),
2776            UserDefinedTypeSqlDefinitionOption::Element(dt) => write!(f, "ELEMENT = {}", dt),
2777            UserDefinedTypeSqlDefinitionOption::Delimiter(s) => {
2778                write!(f, "DELIMITER = '{}'", escape_single_quote_string(s))
2779            }
2780            UserDefinedTypeSqlDefinitionOption::Collatable(b) => write!(f, "COLLATABLE = {}", b),
2781        }
2782    }
2783}
2784
2785/// PARTITION statement used in ALTER TABLE et al. such as in Hive and ClickHouse SQL.
2786/// For example, ClickHouse's OPTIMIZE TABLE supports syntax like PARTITION ID 'partition_id' and PARTITION expr.
2787/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2788#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2789#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2790#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2791pub enum Partition {
2792    /// ClickHouse supports PARTITION ID 'partition_id' syntax.
2793    Identifier(Ident),
2794    /// ClickHouse supports PARTITION expr syntax.
2795    Expr(Expr),
2796    /// ClickHouse supports PART expr which represents physical partition in disk.
2797    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
2798    Part(Expr),
2799    /// Hive supports multiple partitions in PARTITION (part1, part2, ...) syntax.
2800    Partitions(Vec<Expr>),
2801}
2802
2803impl fmt::Display for Partition {
2804    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2805        match self {
2806            Partition::Identifier(id) => write!(f, "PARTITION ID {id}"),
2807            Partition::Expr(expr) => write!(f, "PARTITION {expr}"),
2808            Partition::Part(expr) => write!(f, "PART {expr}"),
2809            Partition::Partitions(partitions) => {
2810                write!(f, "PARTITION ({})", display_comma_separated(partitions))
2811            }
2812        }
2813    }
2814}
2815
2816/// DEDUPLICATE statement used in OPTIMIZE TABLE et al. such as in ClickHouse SQL
2817/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2818#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2819#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2820#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2821pub enum Deduplicate {
2822    /// DEDUPLICATE ALL
2823    All,
2824    /// DEDUPLICATE BY expr
2825    ByExpression(Expr),
2826}
2827
2828impl fmt::Display for Deduplicate {
2829    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2830        match self {
2831            Deduplicate::All => write!(f, "DEDUPLICATE"),
2832            Deduplicate::ByExpression(expr) => write!(f, "DEDUPLICATE BY {expr}"),
2833        }
2834    }
2835}
2836
2837/// Hive supports `CLUSTERED BY` statement in `CREATE TABLE`.
2838/// Syntax: `CLUSTERED BY (col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS`
2839///
2840/// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2841#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2842#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2843#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2844pub struct ClusteredBy {
2845    /// columns used for clustering
2846    pub columns: Vec<Ident>,
2847    /// optional sorted by expressions
2848    pub sorted_by: Option<Vec<OrderByExpr>>,
2849    /// number of buckets
2850    pub num_buckets: Value,
2851}
2852
2853impl fmt::Display for ClusteredBy {
2854    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2855        write!(
2856            f,
2857            "CLUSTERED BY ({})",
2858            display_comma_separated(&self.columns)
2859        )?;
2860        if let Some(ref sorted_by) = self.sorted_by {
2861            write!(f, " SORTED BY ({})", display_comma_separated(sorted_by))?;
2862        }
2863        write!(f, " INTO {} BUCKETS", self.num_buckets)
2864    }
2865}
2866
2867/// CREATE INDEX statement.
2868#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2869#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2870#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2871pub struct CreateIndex {
2872    /// index name
2873    pub name: Option<ObjectName>,
2874    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2875    /// table name
2876    pub table_name: ObjectName,
2877    /// Index type used in the statement. Can also be found inside [`CreateIndex::index_options`]
2878    /// depending on the position of the option within the statement.
2879    pub using: Option<IndexType>,
2880    /// columns included in the index
2881    pub columns: Vec<IndexColumn>,
2882    /// whether the index is unique
2883    pub unique: bool,
2884    /// whether the index is created concurrently
2885    pub concurrently: bool,
2886    /// IF NOT EXISTS clause
2887    pub if_not_exists: bool,
2888    /// INCLUDE clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2889    pub include: Vec<Ident>,
2890    /// NULLS DISTINCT / NOT DISTINCT clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2891    pub nulls_distinct: Option<bool>,
2892    /// WITH clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2893    pub with: Vec<Expr>,
2894    /// WHERE clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2895    pub predicate: Option<Expr>,
2896    /// Index options: <https://www.postgresql.org/docs/current/sql-createindex.html>
2897    pub index_options: Vec<IndexOption>,
2898    /// [MySQL] allows a subset of options normally used for `ALTER TABLE`:
2899    ///
2900    /// - `ALGORITHM`
2901    /// - `LOCK`
2902    ///
2903    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/create-index.html
2904    pub alter_options: Vec<AlterTableOperation>,
2905}
2906
2907impl fmt::Display for CreateIndex {
2908    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2909        write!(
2910            f,
2911            "CREATE {unique}INDEX {concurrently}{if_not_exists}",
2912            unique = if self.unique { "UNIQUE " } else { "" },
2913            concurrently = if self.concurrently {
2914                "CONCURRENTLY "
2915            } else {
2916                ""
2917            },
2918            if_not_exists = if self.if_not_exists {
2919                "IF NOT EXISTS "
2920            } else {
2921                ""
2922            },
2923        )?;
2924        if let Some(value) = &self.name {
2925            write!(f, "{value} ")?;
2926        }
2927        write!(f, "ON {}", self.table_name)?;
2928        if let Some(value) = &self.using {
2929            write!(f, " USING {value} ")?;
2930        }
2931        write!(f, "({})", display_comma_separated(&self.columns))?;
2932        if !self.include.is_empty() {
2933            write!(f, " INCLUDE ({})", display_comma_separated(&self.include))?;
2934        }
2935        if let Some(value) = self.nulls_distinct {
2936            if value {
2937                write!(f, " NULLS DISTINCT")?;
2938            } else {
2939                write!(f, " NULLS NOT DISTINCT")?;
2940            }
2941        }
2942        if !self.with.is_empty() {
2943            write!(f, " WITH ({})", display_comma_separated(&self.with))?;
2944        }
2945        if let Some(predicate) = &self.predicate {
2946            write!(f, " WHERE {predicate}")?;
2947        }
2948        if !self.index_options.is_empty() {
2949            write!(f, " {}", display_separated(&self.index_options, " "))?;
2950        }
2951        if !self.alter_options.is_empty() {
2952            write!(f, " {}", display_separated(&self.alter_options, " "))?;
2953        }
2954        Ok(())
2955    }
2956}
2957
2958/// CREATE TABLE statement.
2959#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2960#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2961#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2962pub struct CreateTable {
2963    /// `OR REPLACE` clause
2964    pub or_replace: bool,
2965    /// `TEMP` or `TEMPORARY` clause
2966    pub temporary: bool,
2967    /// `EXTERNAL` clause
2968    pub external: bool,
2969    /// `DYNAMIC` clause
2970    pub dynamic: bool,
2971    /// `GLOBAL` clause
2972    pub global: Option<bool>,
2973    /// `IF NOT EXISTS` clause
2974    pub if_not_exists: bool,
2975    /// `TRANSIENT` clause
2976    pub transient: bool,
2977    /// `VOLATILE` clause
2978    pub volatile: bool,
2979    /// `ICEBERG` clause
2980    pub iceberg: bool,
2981    /// `SNAPSHOT` clause
2982    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_snapshot_table_statement>
2983    pub snapshot: bool,
2984    /// Table name
2985    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2986    pub name: ObjectName,
2987    /// Column definitions
2988    pub columns: Vec<ColumnDef>,
2989    /// Table constraints
2990    pub constraints: Vec<TableConstraint>,
2991    /// Hive-specific distribution style
2992    pub hive_distribution: HiveDistributionStyle,
2993    /// Hive-specific formats like `ROW FORMAT DELIMITED` or `ROW FORMAT SERDE 'serde_class' WITH SERDEPROPERTIES (...)`
2994    pub hive_formats: Option<HiveFormat>,
2995    /// Table options
2996    pub table_options: CreateTableOptions,
2997    /// General comment for the table
2998    pub file_format: Option<FileFormat>,
2999    /// Location of the table data
3000    pub location: Option<String>,
3001    /// Query used to populate the table
3002    pub query: Option<Box<Query>>,
3003    /// If the table should be created without a rowid (SQLite)
3004    pub without_rowid: bool,
3005    /// `LIKE` clause
3006    pub like: Option<CreateTableLikeKind>,
3007    /// `CLONE` clause
3008    pub clone: Option<ObjectName>,
3009    /// Table version (for systems that support versioned tables)
3010    pub version: Option<TableVersion>,
3011    /// For Hive dialect, the table comment is after the column definitions without `=`,
3012    /// so the `comment` field is optional and different than the comment field in the general options list.
3013    /// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
3014    pub comment: Option<CommentDef>,
3015    /// ClickHouse "ON COMMIT" clause:
3016    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
3017    pub on_commit: Option<OnCommit>,
3018    /// ClickHouse "ON CLUSTER" clause:
3019    /// <https://clickhouse.com/docs/en/sql-reference/distributed-ddl/>
3020    pub on_cluster: Option<Ident>,
3021    /// ClickHouse "PRIMARY KEY " clause.
3022    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
3023    pub primary_key: Option<Box<Expr>>,
3024    /// ClickHouse "ORDER BY " clause. Note that omitted ORDER BY is different
3025    /// than empty (represented as ()), the latter meaning "no sorting".
3026    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
3027    pub order_by: Option<OneOrManyWithParens<Expr>>,
3028    /// BigQuery: A partition expression for the table.
3029    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#partition_expression>
3030    pub partition_by: Option<Box<Expr>>,
3031    /// BigQuery: Table clustering column list.
3032    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#table_option_list>
3033    /// Snowflake: Table clustering list which contains base column, expressions on base columns.
3034    /// <https://docs.snowflake.com/en/user-guide/tables-clustering-keys#defining-a-clustering-key-for-a-table>
3035    pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
3036    /// Hive: Table clustering column list.
3037    /// <https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable>
3038    pub clustered_by: Option<ClusteredBy>,
3039    /// Postgres `INHERITs` clause, which contains the list of tables from which
3040    /// the new table inherits.
3041    /// <https://www.postgresql.org/docs/current/ddl-inherit.html>
3042    /// <https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-INHERITS>
3043    pub inherits: Option<Vec<ObjectName>>,
3044    /// PostgreSQL `PARTITION OF` clause to create a partition of a parent table.
3045    /// Contains the parent table name.
3046    /// <https://www.postgresql.org/docs/current/sql-createtable.html>
3047    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
3048    pub partition_of: Option<ObjectName>,
3049    /// PostgreSQL partition bound specification for PARTITION OF.
3050    /// <https://www.postgresql.org/docs/current/sql-createtable.html>
3051    pub for_values: Option<ForValues>,
3052    /// SQLite "STRICT" clause.
3053    /// if the "STRICT" table-option keyword is added to the end, after the closing ")",
3054    /// then strict typing rules apply to that table.
3055    pub strict: bool,
3056    /// Snowflake "COPY GRANTS" clause
3057    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3058    pub copy_grants: bool,
3059    /// Snowflake "ENABLE_SCHEMA_EVOLUTION" clause
3060    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3061    pub enable_schema_evolution: Option<bool>,
3062    /// Snowflake "CHANGE_TRACKING" clause
3063    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3064    pub change_tracking: Option<bool>,
3065    /// Snowflake "DATA_RETENTION_TIME_IN_DAYS" clause
3066    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3067    pub data_retention_time_in_days: Option<u64>,
3068    /// Snowflake "MAX_DATA_EXTENSION_TIME_IN_DAYS" clause
3069    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3070    pub max_data_extension_time_in_days: Option<u64>,
3071    /// Snowflake "DEFAULT_DDL_COLLATION" clause
3072    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3073    pub default_ddl_collation: Option<String>,
3074    /// Snowflake "WITH AGGREGATION POLICY" clause
3075    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3076    pub with_aggregation_policy: Option<ObjectName>,
3077    /// Snowflake "WITH ROW ACCESS POLICY" clause
3078    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3079    pub with_row_access_policy: Option<RowAccessPolicy>,
3080    /// Snowflake `WITH STORAGE LIFECYCLE POLICY` clause
3081    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3082    pub with_storage_lifecycle_policy: Option<StorageLifecyclePolicy>,
3083    /// Snowflake "WITH TAG" clause
3084    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3085    pub with_tags: Option<Vec<Tag>>,
3086    /// Snowflake "EXTERNAL_VOLUME" clause for Iceberg tables
3087    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3088    pub external_volume: Option<String>,
3089    /// Snowflake "BASE_LOCATION" clause for Iceberg tables
3090    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3091    pub base_location: Option<String>,
3092    /// Snowflake "CATALOG" clause for Iceberg tables
3093    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3094    pub catalog: Option<String>,
3095    /// Snowflake "CATALOG_SYNC" clause for Iceberg tables
3096    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3097    pub catalog_sync: Option<String>,
3098    /// Snowflake "STORAGE_SERIALIZATION_POLICY" clause for Iceberg tables
3099    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3100    pub storage_serialization_policy: Option<StorageSerializationPolicy>,
3101    /// Snowflake "TARGET_LAG" clause for dybamic tables
3102    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3103    pub target_lag: Option<String>,
3104    /// Snowflake "WAREHOUSE" clause for dybamic tables
3105    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3106    pub warehouse: Option<Ident>,
3107    /// Snowflake "REFRESH_MODE" clause for dybamic tables
3108    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3109    pub refresh_mode: Option<RefreshModeKind>,
3110    /// Snowflake "INITIALIZE" clause for dybamic tables
3111    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3112    pub initialize: Option<InitializeKind>,
3113    /// Snowflake "REQUIRE USER" clause for dybamic tables
3114    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3115    pub require_user: bool,
3116    /// Redshift `DISTSTYLE` option
3117    /// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3118    pub diststyle: Option<DistStyle>,
3119    /// Redshift `DISTKEY` option
3120    /// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3121    pub distkey: Option<Expr>,
3122    /// Redshift `SORTKEY` option
3123    /// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3124    pub sortkey: Option<Vec<Expr>>,
3125    /// Redshift `BACKUP` option: `BACKUP { YES | NO }`
3126    /// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3127    pub backup: Option<bool>,
3128}
3129
3130impl fmt::Display for CreateTable {
3131    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3132        // We want to allow the following options
3133        // Empty column list, allowed by PostgreSQL:
3134        //   `CREATE TABLE t ()`
3135        // No columns provided for CREATE TABLE AS:
3136        //   `CREATE TABLE t AS SELECT a from t2`
3137        // Columns provided for CREATE TABLE AS:
3138        //   `CREATE TABLE t (a INT) AS SELECT a from t2`
3139        write!(
3140            f,
3141            "CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}{dynamic}{iceberg}{snapshot}TABLE {if_not_exists}{name}",
3142            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
3143            external = if self.external { "EXTERNAL " } else { "" },
3144            snapshot = if self.snapshot { "SNAPSHOT " } else { "" },
3145            global = self.global
3146                .map(|global| {
3147                    if global {
3148                        "GLOBAL "
3149                    } else {
3150                        "LOCAL "
3151                    }
3152                })
3153                .unwrap_or(""),
3154            if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
3155            temporary = if self.temporary { "TEMPORARY " } else { "" },
3156            transient = if self.transient { "TRANSIENT " } else { "" },
3157            volatile = if self.volatile { "VOLATILE " } else { "" },
3158            // Only for Snowflake
3159            iceberg = if self.iceberg { "ICEBERG " } else { "" },
3160            dynamic = if self.dynamic { "DYNAMIC " } else { "" },
3161            name = self.name,
3162        )?;
3163        if let Some(partition_of) = &self.partition_of {
3164            write!(f, " PARTITION OF {partition_of}")?;
3165        }
3166        if let Some(on_cluster) = &self.on_cluster {
3167            write!(f, " ON CLUSTER {on_cluster}")?;
3168        }
3169        if !self.columns.is_empty() || !self.constraints.is_empty() {
3170            f.write_str(" (")?;
3171            NewLine.fmt(f)?;
3172            Indent(DisplayCommaSeparated(&self.columns)).fmt(f)?;
3173            if !self.columns.is_empty() && !self.constraints.is_empty() {
3174                f.write_str(",")?;
3175                SpaceOrNewline.fmt(f)?;
3176            }
3177            Indent(DisplayCommaSeparated(&self.constraints)).fmt(f)?;
3178            NewLine.fmt(f)?;
3179            f.write_str(")")?;
3180        } else if self.query.is_none()
3181            && self.like.is_none()
3182            && self.clone.is_none()
3183            && self.partition_of.is_none()
3184        {
3185            // PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
3186            f.write_str(" ()")?;
3187        } else if let Some(CreateTableLikeKind::Parenthesized(like_in_columns_list)) = &self.like {
3188            write!(f, " ({like_in_columns_list})")?;
3189        }
3190        if let Some(for_values) = &self.for_values {
3191            write!(f, " {for_values}")?;
3192        }
3193
3194        // Hive table comment should be after column definitions, please refer to:
3195        // [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
3196        if let Some(comment) = &self.comment {
3197            write!(f, " COMMENT '{comment}'")?;
3198        }
3199
3200        // Only for SQLite
3201        if self.without_rowid {
3202            write!(f, " WITHOUT ROWID")?;
3203        }
3204
3205        if let Some(CreateTableLikeKind::Plain(like)) = &self.like {
3206            write!(f, " {like}")?;
3207        }
3208
3209        if let Some(c) = &self.clone {
3210            write!(f, " CLONE {c}")?;
3211        }
3212
3213        if let Some(version) = &self.version {
3214            write!(f, " {version}")?;
3215        }
3216
3217        match &self.hive_distribution {
3218            HiveDistributionStyle::PARTITIONED { columns } => {
3219                write!(f, " PARTITIONED BY ({})", display_comma_separated(columns))?;
3220            }
3221            HiveDistributionStyle::SKEWED {
3222                columns,
3223                on,
3224                stored_as_directories,
3225            } => {
3226                write!(
3227                    f,
3228                    " SKEWED BY ({})) ON ({})",
3229                    display_comma_separated(columns),
3230                    display_comma_separated(on)
3231                )?;
3232                if *stored_as_directories {
3233                    write!(f, " STORED AS DIRECTORIES")?;
3234                }
3235            }
3236            _ => (),
3237        }
3238
3239        if let Some(clustered_by) = &self.clustered_by {
3240            write!(f, " {clustered_by}")?;
3241        }
3242
3243        if let Some(HiveFormat {
3244            row_format,
3245            serde_properties,
3246            storage,
3247            location,
3248        }) = &self.hive_formats
3249        {
3250            match row_format {
3251                Some(HiveRowFormat::SERDE { class }) => write!(f, " ROW FORMAT SERDE '{class}'")?,
3252                Some(HiveRowFormat::DELIMITED { delimiters }) => {
3253                    write!(f, " ROW FORMAT DELIMITED")?;
3254                    if !delimiters.is_empty() {
3255                        write!(f, " {}", display_separated(delimiters, " "))?;
3256                    }
3257                }
3258                None => (),
3259            }
3260            match storage {
3261                Some(HiveIOFormat::IOF {
3262                    input_format,
3263                    output_format,
3264                }) => write!(
3265                    f,
3266                    " STORED AS INPUTFORMAT {input_format} OUTPUTFORMAT {output_format}"
3267                )?,
3268                Some(HiveIOFormat::FileFormat { format }) if !self.external => {
3269                    write!(f, " STORED AS {format}")?
3270                }
3271                _ => (),
3272            }
3273            if let Some(serde_properties) = serde_properties.as_ref() {
3274                write!(
3275                    f,
3276                    " WITH SERDEPROPERTIES ({})",
3277                    display_comma_separated(serde_properties)
3278                )?;
3279            }
3280            if !self.external {
3281                if let Some(loc) = location {
3282                    write!(f, " LOCATION '{loc}'")?;
3283                }
3284            }
3285        }
3286        if self.external {
3287            if let Some(file_format) = self.file_format {
3288                write!(f, " STORED AS {file_format}")?;
3289            }
3290            if let Some(location) = &self.location {
3291                write!(f, " LOCATION '{location}'")?;
3292            }
3293        }
3294
3295        match &self.table_options {
3296            options @ CreateTableOptions::With(_)
3297            | options @ CreateTableOptions::Plain(_)
3298            | options @ CreateTableOptions::TableProperties(_) => write!(f, " {options}")?,
3299            _ => (),
3300        }
3301
3302        if let Some(primary_key) = &self.primary_key {
3303            write!(f, " PRIMARY KEY {primary_key}")?;
3304        }
3305        if let Some(order_by) = &self.order_by {
3306            write!(f, " ORDER BY {order_by}")?;
3307        }
3308        if let Some(inherits) = &self.inherits {
3309            write!(f, " INHERITS ({})", display_comma_separated(inherits))?;
3310        }
3311        if let Some(partition_by) = self.partition_by.as_ref() {
3312            write!(f, " PARTITION BY {partition_by}")?;
3313        }
3314        if let Some(cluster_by) = self.cluster_by.as_ref() {
3315            write!(f, " CLUSTER BY {cluster_by}")?;
3316        }
3317        if let options @ CreateTableOptions::Options(_) = &self.table_options {
3318            write!(f, " {options}")?;
3319        }
3320        if let Some(external_volume) = self.external_volume.as_ref() {
3321            write!(f, " EXTERNAL_VOLUME='{external_volume}'")?;
3322        }
3323
3324        if let Some(catalog) = self.catalog.as_ref() {
3325            write!(f, " CATALOG='{catalog}'")?;
3326        }
3327
3328        if self.iceberg {
3329            if let Some(base_location) = self.base_location.as_ref() {
3330                write!(f, " BASE_LOCATION='{base_location}'")?;
3331            }
3332        }
3333
3334        if let Some(catalog_sync) = self.catalog_sync.as_ref() {
3335            write!(f, " CATALOG_SYNC='{catalog_sync}'")?;
3336        }
3337
3338        if let Some(storage_serialization_policy) = self.storage_serialization_policy.as_ref() {
3339            write!(
3340                f,
3341                " STORAGE_SERIALIZATION_POLICY={storage_serialization_policy}"
3342            )?;
3343        }
3344
3345        if self.copy_grants {
3346            write!(f, " COPY GRANTS")?;
3347        }
3348
3349        if let Some(is_enabled) = self.enable_schema_evolution {
3350            write!(
3351                f,
3352                " ENABLE_SCHEMA_EVOLUTION={}",
3353                if is_enabled { "TRUE" } else { "FALSE" }
3354            )?;
3355        }
3356
3357        if let Some(is_enabled) = self.change_tracking {
3358            write!(
3359                f,
3360                " CHANGE_TRACKING={}",
3361                if is_enabled { "TRUE" } else { "FALSE" }
3362            )?;
3363        }
3364
3365        if let Some(data_retention_time_in_days) = self.data_retention_time_in_days {
3366            write!(
3367                f,
3368                " DATA_RETENTION_TIME_IN_DAYS={data_retention_time_in_days}",
3369            )?;
3370        }
3371
3372        if let Some(max_data_extension_time_in_days) = self.max_data_extension_time_in_days {
3373            write!(
3374                f,
3375                " MAX_DATA_EXTENSION_TIME_IN_DAYS={max_data_extension_time_in_days}",
3376            )?;
3377        }
3378
3379        if let Some(default_ddl_collation) = &self.default_ddl_collation {
3380            write!(f, " DEFAULT_DDL_COLLATION='{default_ddl_collation}'",)?;
3381        }
3382
3383        if let Some(with_aggregation_policy) = &self.with_aggregation_policy {
3384            write!(f, " WITH AGGREGATION POLICY {with_aggregation_policy}",)?;
3385        }
3386
3387        if let Some(row_access_policy) = &self.with_row_access_policy {
3388            write!(f, " {row_access_policy}",)?;
3389        }
3390
3391        if let Some(storage_lifecycle_policy) = &self.with_storage_lifecycle_policy {
3392            write!(f, " {storage_lifecycle_policy}",)?;
3393        }
3394
3395        if let Some(tag) = &self.with_tags {
3396            write!(f, " WITH TAG ({})", display_comma_separated(tag.as_slice()))?;
3397        }
3398
3399        if let Some(target_lag) = &self.target_lag {
3400            write!(f, " TARGET_LAG='{target_lag}'")?;
3401        }
3402
3403        if let Some(warehouse) = &self.warehouse {
3404            write!(f, " WAREHOUSE={warehouse}")?;
3405        }
3406
3407        if let Some(refresh_mode) = &self.refresh_mode {
3408            write!(f, " REFRESH_MODE={refresh_mode}")?;
3409        }
3410
3411        if let Some(initialize) = &self.initialize {
3412            write!(f, " INITIALIZE={initialize}")?;
3413        }
3414
3415        if self.require_user {
3416            write!(f, " REQUIRE USER")?;
3417        }
3418
3419        if self.on_commit.is_some() {
3420            let on_commit = match self.on_commit {
3421                Some(OnCommit::DeleteRows) => "ON COMMIT DELETE ROWS",
3422                Some(OnCommit::PreserveRows) => "ON COMMIT PRESERVE ROWS",
3423                Some(OnCommit::Drop) => "ON COMMIT DROP",
3424                None => "",
3425            };
3426            write!(f, " {on_commit}")?;
3427        }
3428        if self.strict {
3429            write!(f, " STRICT")?;
3430        }
3431        if let Some(backup) = self.backup {
3432            write!(f, " BACKUP {}", if backup { "YES" } else { "NO" })?;
3433        }
3434        if let Some(diststyle) = &self.diststyle {
3435            write!(f, " DISTSTYLE {diststyle}")?;
3436        }
3437        if let Some(distkey) = &self.distkey {
3438            write!(f, " DISTKEY({distkey})")?;
3439        }
3440        if let Some(sortkey) = &self.sortkey {
3441            write!(f, " SORTKEY({})", display_comma_separated(sortkey))?;
3442        }
3443        if let Some(query) = &self.query {
3444            write!(f, " AS {query}")?;
3445        }
3446        Ok(())
3447    }
3448}
3449
3450/// PostgreSQL partition bound specification for `PARTITION OF`.
3451///
3452/// Specifies partition bounds for a child partition table.
3453///
3454/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createtable.html)
3455#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3456#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3457#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3458pub enum ForValues {
3459    /// `FOR VALUES IN (expr, ...)`
3460    In(Vec<Expr>),
3461    /// `FOR VALUES FROM (expr|MINVALUE|MAXVALUE, ...) TO (expr|MINVALUE|MAXVALUE, ...)`
3462    From {
3463        /// The lower bound values for the partition.
3464        from: Vec<PartitionBoundValue>,
3465        /// The upper bound values for the partition.
3466        to: Vec<PartitionBoundValue>,
3467    },
3468    /// `FOR VALUES WITH (MODULUS n, REMAINDER r)`
3469    With {
3470        /// The modulus value for hash partitioning.
3471        modulus: u64,
3472        /// The remainder value for hash partitioning.
3473        remainder: u64,
3474    },
3475    /// `DEFAULT`
3476    Default,
3477}
3478
3479impl fmt::Display for ForValues {
3480    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3481        match self {
3482            ForValues::In(values) => {
3483                write!(f, "FOR VALUES IN ({})", display_comma_separated(values))
3484            }
3485            ForValues::From { from, to } => {
3486                write!(
3487                    f,
3488                    "FOR VALUES FROM ({}) TO ({})",
3489                    display_comma_separated(from),
3490                    display_comma_separated(to)
3491                )
3492            }
3493            ForValues::With { modulus, remainder } => {
3494                write!(
3495                    f,
3496                    "FOR VALUES WITH (MODULUS {modulus}, REMAINDER {remainder})"
3497                )
3498            }
3499            ForValues::Default => write!(f, "DEFAULT"),
3500        }
3501    }
3502}
3503
3504/// A value in a partition bound specification.
3505///
3506/// Used in RANGE partition bounds where values can be expressions,
3507/// MINVALUE (negative infinity), or MAXVALUE (positive infinity).
3508#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3509#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3510#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3511pub enum PartitionBoundValue {
3512    /// An expression representing a partition bound value.
3513    Expr(Expr),
3514    /// Represents negative infinity in partition bounds.
3515    MinValue,
3516    /// Represents positive infinity in partition bounds.
3517    MaxValue,
3518}
3519
3520impl fmt::Display for PartitionBoundValue {
3521    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3522        match self {
3523            PartitionBoundValue::Expr(expr) => write!(f, "{expr}"),
3524            PartitionBoundValue::MinValue => write!(f, "MINVALUE"),
3525            PartitionBoundValue::MaxValue => write!(f, "MAXVALUE"),
3526        }
3527    }
3528}
3529
3530/// Redshift distribution style for `CREATE TABLE`.
3531///
3532/// See [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html)
3533#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3534#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3535#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3536pub enum DistStyle {
3537    /// `DISTSTYLE AUTO`
3538    Auto,
3539    /// `DISTSTYLE EVEN`
3540    Even,
3541    /// `DISTSTYLE KEY`
3542    Key,
3543    /// `DISTSTYLE ALL`
3544    All,
3545}
3546
3547impl fmt::Display for DistStyle {
3548    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3549        match self {
3550            DistStyle::Auto => write!(f, "AUTO"),
3551            DistStyle::Even => write!(f, "EVEN"),
3552            DistStyle::Key => write!(f, "KEY"),
3553            DistStyle::All => write!(f, "ALL"),
3554        }
3555    }
3556}
3557
3558
3559#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3560#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3561#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3562/// ```sql
3563/// CREATE DOMAIN name [ AS ] data_type
3564///         [ COLLATE collation ]
3565///         [ DEFAULT expression ]
3566///         [ domain_constraint [ ... ] ]
3567///
3568///     where domain_constraint is:
3569///
3570///     [ CONSTRAINT constraint_name ]
3571///     { NOT NULL | NULL | CHECK (expression) }
3572/// ```
3573/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createdomain.html)
3574pub struct CreateDomain {
3575    /// The name of the domain to be created.
3576    pub name: ObjectName,
3577    /// The data type of the domain.
3578    pub data_type: DataType,
3579    /// The collation of the domain.
3580    pub collation: Option<Ident>,
3581    /// The default value of the domain.
3582    pub default: Option<Expr>,
3583    /// The constraints of the domain.
3584    pub constraints: Vec<TableConstraint>,
3585}
3586
3587impl fmt::Display for CreateDomain {
3588    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3589        write!(
3590            f,
3591            "CREATE DOMAIN {name} AS {data_type}",
3592            name = self.name,
3593            data_type = self.data_type
3594        )?;
3595        if let Some(collation) = &self.collation {
3596            write!(f, " COLLATE {collation}")?;
3597        }
3598        if let Some(default) = &self.default {
3599            write!(f, " DEFAULT {default}")?;
3600        }
3601        if !self.constraints.is_empty() {
3602            write!(f, " {}", display_separated(&self.constraints, " "))?;
3603        }
3604        Ok(())
3605    }
3606}
3607
3608/// The return type of a `CREATE FUNCTION` statement.
3609#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3610#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3611#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3612pub enum FunctionReturnType {
3613    /// `RETURNS <type>`
3614    DataType(DataType),
3615    /// `RETURNS SETOF <type>`
3616    ///
3617    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3618    SetOf(DataType),
3619}
3620
3621impl fmt::Display for FunctionReturnType {
3622    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3623        match self {
3624            FunctionReturnType::DataType(data_type) => write!(f, "{data_type}"),
3625            FunctionReturnType::SetOf(data_type) => write!(f, "SETOF {data_type}"),
3626        }
3627    }
3628}
3629
3630#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3631#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3632#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3633/// CREATE FUNCTION statement
3634pub struct CreateFunction {
3635    /// True if this is a `CREATE OR ALTER FUNCTION` statement
3636    ///
3637    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql?view=sql-server-ver16#or-alter)
3638    pub or_alter: bool,
3639    /// True if this is a `CREATE OR REPLACE FUNCTION` statement
3640    pub or_replace: bool,
3641    /// True if this is a `CREATE TEMPORARY FUNCTION` statement
3642    pub temporary: bool,
3643    /// True if this is a `CREATE IF NOT EXISTS FUNCTION` statement
3644    pub if_not_exists: bool,
3645    /// Name of the function to be created.
3646    pub name: ObjectName,
3647    /// List of arguments for the function.
3648    pub args: Option<Vec<OperateFunctionArg>>,
3649    /// The return type of the function.
3650    pub return_type: Option<FunctionReturnType>,
3651    /// The expression that defines the function.
3652    ///
3653    /// Examples:
3654    /// ```sql
3655    /// AS ((SELECT 1))
3656    /// AS "console.log();"
3657    /// ```
3658    pub function_body: Option<CreateFunctionBody>,
3659    /// Behavior attribute for the function
3660    ///
3661    /// IMMUTABLE | STABLE | VOLATILE
3662    ///
3663    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3664    pub behavior: Option<FunctionBehavior>,
3665    /// CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
3666    ///
3667    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3668    pub called_on_null: Option<FunctionCalledOnNull>,
3669    /// PARALLEL { UNSAFE | RESTRICTED | SAFE }
3670    ///
3671    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3672    pub parallel: Option<FunctionParallel>,
3673    /// SECURITY { DEFINER | INVOKER }
3674    ///
3675    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3676    pub security: Option<FunctionSecurity>,
3677    /// SET configuration_parameter clauses
3678    ///
3679    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3680    pub set_params: Vec<FunctionDefinitionSetParam>,
3681    /// USING ... (Hive only)
3682    pub using: Option<CreateFunctionUsing>,
3683    /// Language used in a UDF definition.
3684    ///
3685    /// Example:
3686    /// ```sql
3687    /// CREATE FUNCTION foo() LANGUAGE js AS "console.log();"
3688    /// ```
3689    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_javascript_udf)
3690    pub language: Option<Ident>,
3691    /// Determinism keyword used for non-sql UDF definitions.
3692    ///
3693    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
3694    pub determinism_specifier: Option<FunctionDeterminismSpecifier>,
3695    /// List of options for creating the function.
3696    ///
3697    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
3698    pub options: Option<Vec<SqlOption>>,
3699    /// Connection resource for a remote function.
3700    ///
3701    /// Example:
3702    /// ```sql
3703    /// CREATE FUNCTION foo()
3704    /// RETURNS FLOAT64
3705    /// REMOTE WITH CONNECTION us.myconnection
3706    /// ```
3707    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
3708    pub remote_connection: Option<ObjectName>,
3709}
3710
3711impl fmt::Display for CreateFunction {
3712    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3713        write!(
3714            f,
3715            "CREATE {or_alter}{or_replace}{temp}FUNCTION {if_not_exists}{name}",
3716            name = self.name,
3717            temp = if self.temporary { "TEMPORARY " } else { "" },
3718            or_alter = if self.or_alter { "OR ALTER " } else { "" },
3719            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
3720            if_not_exists = if self.if_not_exists {
3721                "IF NOT EXISTS "
3722            } else {
3723                ""
3724            },
3725        )?;
3726        if let Some(args) = &self.args {
3727            write!(f, "({})", display_comma_separated(args))?;
3728        }
3729        if let Some(return_type) = &self.return_type {
3730            write!(f, " RETURNS {return_type}")?;
3731        }
3732        if let Some(determinism_specifier) = &self.determinism_specifier {
3733            write!(f, " {determinism_specifier}")?;
3734        }
3735        if let Some(language) = &self.language {
3736            write!(f, " LANGUAGE {language}")?;
3737        }
3738        if let Some(behavior) = &self.behavior {
3739            write!(f, " {behavior}")?;
3740        }
3741        if let Some(called_on_null) = &self.called_on_null {
3742            write!(f, " {called_on_null}")?;
3743        }
3744        if let Some(parallel) = &self.parallel {
3745            write!(f, " {parallel}")?;
3746        }
3747        if let Some(security) = &self.security {
3748            write!(f, " {security}")?;
3749        }
3750        for set_param in &self.set_params {
3751            write!(f, " {set_param}")?;
3752        }
3753        if let Some(remote_connection) = &self.remote_connection {
3754            write!(f, " REMOTE WITH CONNECTION {remote_connection}")?;
3755        }
3756        if let Some(CreateFunctionBody::AsBeforeOptions { body, link_symbol }) = &self.function_body
3757        {
3758            write!(f, " AS {body}")?;
3759            if let Some(link_symbol) = link_symbol {
3760                write!(f, ", {link_symbol}")?;
3761            }
3762        }
3763        if let Some(CreateFunctionBody::Return(function_body)) = &self.function_body {
3764            write!(f, " RETURN {function_body}")?;
3765        }
3766        if let Some(CreateFunctionBody::AsReturnExpr(function_body)) = &self.function_body {
3767            write!(f, " AS RETURN {function_body}")?;
3768        }
3769        if let Some(CreateFunctionBody::AsReturnSelect(function_body)) = &self.function_body {
3770            write!(f, " AS RETURN {function_body}")?;
3771        }
3772        if let Some(using) = &self.using {
3773            write!(f, " {using}")?;
3774        }
3775        if let Some(options) = &self.options {
3776            write!(
3777                f,
3778                " OPTIONS({})",
3779                display_comma_separated(options.as_slice())
3780            )?;
3781        }
3782        if let Some(CreateFunctionBody::AsAfterOptions(function_body)) = &self.function_body {
3783            write!(f, " AS {function_body}")?;
3784        }
3785        if let Some(CreateFunctionBody::AsBeginEnd(bes)) = &self.function_body {
3786            write!(f, " AS {bes}")?;
3787        }
3788        Ok(())
3789    }
3790}
3791
3792/// ```sql
3793/// CREATE CONNECTOR [IF NOT EXISTS] connector_name
3794/// [TYPE datasource_type]
3795/// [URL datasource_url]
3796/// [COMMENT connector_comment]
3797/// [WITH DCPROPERTIES(property_name=property_value, ...)]
3798/// ```
3799///
3800/// [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
3801#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3802#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3803#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3804pub struct CreateConnector {
3805    /// The name of the connector to be created.
3806    pub name: Ident,
3807    /// Whether `IF NOT EXISTS` was specified.
3808    pub if_not_exists: bool,
3809    /// The type of the connector.
3810    pub connector_type: Option<String>,
3811    /// The URL of the connector.
3812    pub url: Option<String>,
3813    /// The comment for the connector.
3814    pub comment: Option<CommentDef>,
3815    /// The DC properties for the connector.
3816    pub with_dcproperties: Option<Vec<SqlOption>>,
3817}
3818
3819impl fmt::Display for CreateConnector {
3820    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3821        write!(
3822            f,
3823            "CREATE CONNECTOR {if_not_exists}{name}",
3824            if_not_exists = if self.if_not_exists {
3825                "IF NOT EXISTS "
3826            } else {
3827                ""
3828            },
3829            name = self.name,
3830        )?;
3831
3832        if let Some(connector_type) = &self.connector_type {
3833            write!(f, " TYPE '{connector_type}'")?;
3834        }
3835
3836        if let Some(url) = &self.url {
3837            write!(f, " URL '{url}'")?;
3838        }
3839
3840        if let Some(comment) = &self.comment {
3841            write!(f, " COMMENT = '{comment}'")?;
3842        }
3843
3844        if let Some(with_dcproperties) = &self.with_dcproperties {
3845            write!(
3846                f,
3847                " WITH DCPROPERTIES({})",
3848                display_comma_separated(with_dcproperties)
3849            )?;
3850        }
3851
3852        Ok(())
3853    }
3854}
3855
3856/// An `ALTER SCHEMA` (`Statement::AlterSchema`) operation.
3857///
3858/// See [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#alter_schema_collate_statement)
3859/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterschema.html)
3860#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3861#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3862#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3863pub enum AlterSchemaOperation {
3864    /// Set the default collation for the schema.
3865    SetDefaultCollate {
3866        /// The collation to set as default.
3867        collate: Expr,
3868    },
3869    /// Add a replica to the schema.
3870    AddReplica {
3871        /// The replica to add.
3872        replica: Ident,
3873        /// Optional options for the replica.
3874        options: Option<Vec<SqlOption>>,
3875    },
3876    /// Drop a replica from the schema.
3877    DropReplica {
3878        /// The replica to drop.
3879        replica: Ident,
3880    },
3881    /// Set options for the schema.
3882    SetOptionsParens {
3883        /// The options to set.
3884        options: Vec<SqlOption>,
3885    },
3886    /// Rename the schema.
3887    Rename {
3888        /// The new name for the schema.
3889        name: ObjectName,
3890    },
3891    /// Change the owner of the schema.
3892    OwnerTo {
3893        /// The new owner of the schema.
3894        owner: Owner,
3895    },
3896}
3897
3898impl fmt::Display for AlterSchemaOperation {
3899    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3900        match self {
3901            AlterSchemaOperation::SetDefaultCollate { collate } => {
3902                write!(f, "SET DEFAULT COLLATE {collate}")
3903            }
3904            AlterSchemaOperation::AddReplica { replica, options } => {
3905                write!(f, "ADD REPLICA {replica}")?;
3906                if let Some(options) = options {
3907                    write!(f, " OPTIONS ({})", display_comma_separated(options))?;
3908                }
3909                Ok(())
3910            }
3911            AlterSchemaOperation::DropReplica { replica } => write!(f, "DROP REPLICA {replica}"),
3912            AlterSchemaOperation::SetOptionsParens { options } => {
3913                write!(f, "SET OPTIONS ({})", display_comma_separated(options))
3914            }
3915            AlterSchemaOperation::Rename { name } => write!(f, "RENAME TO {name}"),
3916            AlterSchemaOperation::OwnerTo { owner } => write!(f, "OWNER TO {owner}"),
3917        }
3918    }
3919}
3920/// `RenameTableNameKind` is the kind used in an `ALTER TABLE _ RENAME` statement.
3921///
3922/// Note: [MySQL] is the only database that supports the AS keyword for this operation.
3923///
3924/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
3925#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3926#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3927#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3928pub enum RenameTableNameKind {
3929    /// `AS new_table_name`
3930    As(ObjectName),
3931    /// `TO new_table_name`
3932    To(ObjectName),
3933}
3934
3935impl fmt::Display for RenameTableNameKind {
3936    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3937        match self {
3938            RenameTableNameKind::As(name) => write!(f, "AS {name}"),
3939            RenameTableNameKind::To(name) => write!(f, "TO {name}"),
3940        }
3941    }
3942}
3943
3944#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3945#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3946#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3947/// An `ALTER SCHEMA` (`Statement::AlterSchema`) statement.
3948pub struct AlterSchema {
3949    /// The schema name to alter.
3950    pub name: ObjectName,
3951    /// Whether `IF EXISTS` was specified.
3952    pub if_exists: bool,
3953    /// The list of operations to perform on the schema.
3954    pub operations: Vec<AlterSchemaOperation>,
3955}
3956
3957impl fmt::Display for AlterSchema {
3958    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3959        write!(f, "ALTER SCHEMA ")?;
3960        if self.if_exists {
3961            write!(f, "IF EXISTS ")?;
3962        }
3963        write!(f, "{}", self.name)?;
3964        for operation in &self.operations {
3965            write!(f, " {operation}")?;
3966        }
3967
3968        Ok(())
3969    }
3970}
3971
3972impl Spanned for RenameTableNameKind {
3973    fn span(&self) -> Span {
3974        match self {
3975            RenameTableNameKind::As(name) => name.span(),
3976            RenameTableNameKind::To(name) => name.span(),
3977        }
3978    }
3979}
3980
3981#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
3982#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3983#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3984/// Whether the syntax used for the trigger object (ROW or STATEMENT) is `FOR` or `FOR EACH`.
3985pub enum TriggerObjectKind {
3986    /// The `FOR` syntax is used.
3987    For(TriggerObject),
3988    /// The `FOR EACH` syntax is used.
3989    ForEach(TriggerObject),
3990}
3991
3992impl Display for TriggerObjectKind {
3993    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3994        match self {
3995            TriggerObjectKind::For(obj) => write!(f, "FOR {obj}"),
3996            TriggerObjectKind::ForEach(obj) => write!(f, "FOR EACH {obj}"),
3997        }
3998    }
3999}
4000
4001#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4002#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4003#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4004/// CREATE TRIGGER
4005///
4006/// Examples:
4007///
4008/// ```sql
4009/// CREATE TRIGGER trigger_name
4010/// BEFORE INSERT ON table_name
4011/// FOR EACH ROW
4012/// EXECUTE FUNCTION trigger_function();
4013/// ```
4014///
4015/// Postgres: <https://www.postgresql.org/docs/current/sql-createtrigger.html>
4016/// SQL Server: <https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql>
4017pub struct CreateTrigger {
4018    /// True if this is a `CREATE OR ALTER TRIGGER` statement
4019    ///
4020    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql?view=sql-server-ver16#arguments)
4021    pub or_alter: bool,
4022    /// True if this is a temporary trigger.
4023    ///
4024    /// Examples:
4025    ///
4026    /// ```sql
4027    /// CREATE TEMP TRIGGER trigger_name
4028    /// ```
4029    ///
4030    /// or
4031    ///
4032    /// ```sql
4033    /// CREATE TEMPORARY TRIGGER trigger_name;
4034    /// CREATE TEMP TRIGGER trigger_name;
4035    /// ```
4036    ///
4037    /// [SQLite](https://sqlite.org/lang_createtrigger.html#temp_triggers_on_non_temp_tables)
4038    pub temporary: bool,
4039    /// The `OR REPLACE` clause is used to re-create the trigger if it already exists.
4040    ///
4041    /// Example:
4042    /// ```sql
4043    /// CREATE OR REPLACE TRIGGER trigger_name
4044    /// AFTER INSERT ON table_name
4045    /// FOR EACH ROW
4046    /// EXECUTE FUNCTION trigger_function();
4047    /// ```
4048    pub or_replace: bool,
4049    /// The `CONSTRAINT` keyword is used to create a trigger as a constraint.
4050    pub is_constraint: bool,
4051    /// The name of the trigger to be created.
4052    pub name: ObjectName,
4053    /// Determines whether the function is called before, after, or instead of the event.
4054    ///
4055    /// Example of BEFORE:
4056    ///
4057    /// ```sql
4058    /// CREATE TRIGGER trigger_name
4059    /// BEFORE INSERT ON table_name
4060    /// FOR EACH ROW
4061    /// EXECUTE FUNCTION trigger_function();
4062    /// ```
4063    ///
4064    /// Example of AFTER:
4065    ///
4066    /// ```sql
4067    /// CREATE TRIGGER trigger_name
4068    /// AFTER INSERT ON table_name
4069    /// FOR EACH ROW
4070    /// EXECUTE FUNCTION trigger_function();
4071    /// ```
4072    ///
4073    /// Example of INSTEAD OF:
4074    ///
4075    /// ```sql
4076    /// CREATE TRIGGER trigger_name
4077    /// INSTEAD OF INSERT ON table_name
4078    /// FOR EACH ROW
4079    /// EXECUTE FUNCTION trigger_function();
4080    /// ```
4081    pub period: Option<TriggerPeriod>,
4082    /// Whether the trigger period was specified before the target table name.
4083    /// This does not refer to whether the period is BEFORE, AFTER, or INSTEAD OF,
4084    /// but rather the position of the period clause in relation to the table name.
4085    ///
4086    /// ```sql
4087    /// -- period_before_table == true: Postgres, MySQL, and standard SQL
4088    /// CREATE TRIGGER t BEFORE INSERT ON table_name ...;
4089    /// -- period_before_table == false: MSSQL
4090    /// CREATE TRIGGER t ON table_name BEFORE INSERT ...;
4091    /// ```
4092    pub period_before_table: bool,
4093    /// Multiple events can be specified using OR, such as `INSERT`, `UPDATE`, `DELETE`, or `TRUNCATE`.
4094    pub events: Vec<TriggerEvent>,
4095    /// The table on which the trigger is to be created.
4096    pub table_name: ObjectName,
4097    /// The optional referenced table name that can be referenced via
4098    /// the `FROM` keyword.
4099    pub referenced_table_name: Option<ObjectName>,
4100    /// This keyword immediately precedes the declaration of one or two relation names that provide access to the transition relations of the triggering statement.
4101    pub referencing: Vec<TriggerReferencing>,
4102    /// This specifies whether the trigger function should be fired once for
4103    /// every row affected by the trigger event, or just once per SQL statement.
4104    /// This is optional in some SQL dialects, such as SQLite, and if not specified, in
4105    /// those cases, the implied default is `FOR EACH ROW`.
4106    pub trigger_object: Option<TriggerObjectKind>,
4107    ///  Triggering conditions
4108    pub condition: Option<Expr>,
4109    /// Execute logic block
4110    pub exec_body: Option<TriggerExecBody>,
4111    /// For MSSQL and dialects where statements are preceded by `AS`
4112    pub statements_as: bool,
4113    /// For SQL dialects with statement(s) for a body
4114    pub statements: Option<ConditionalStatements>,
4115    /// The characteristic of the trigger, which include whether the trigger is `DEFERRABLE`, `INITIALLY DEFERRED`, or `INITIALLY IMMEDIATE`,
4116    pub characteristics: Option<ConstraintCharacteristics>,
4117}
4118
4119impl Display for CreateTrigger {
4120    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4121        let CreateTrigger {
4122            or_alter,
4123            temporary,
4124            or_replace,
4125            is_constraint,
4126            name,
4127            period_before_table,
4128            period,
4129            events,
4130            table_name,
4131            referenced_table_name,
4132            referencing,
4133            trigger_object,
4134            condition,
4135            exec_body,
4136            statements_as,
4137            statements,
4138            characteristics,
4139        } = self;
4140        write!(
4141            f,
4142            "CREATE {temporary}{or_alter}{or_replace}{is_constraint}TRIGGER {name} ",
4143            temporary = if *temporary { "TEMPORARY " } else { "" },
4144            or_alter = if *or_alter { "OR ALTER " } else { "" },
4145            or_replace = if *or_replace { "OR REPLACE " } else { "" },
4146            is_constraint = if *is_constraint { "CONSTRAINT " } else { "" },
4147        )?;
4148
4149        if *period_before_table {
4150            if let Some(p) = period {
4151                write!(f, "{p} ")?;
4152            }
4153            if !events.is_empty() {
4154                write!(f, "{} ", display_separated(events, " OR "))?;
4155            }
4156            write!(f, "ON {table_name}")?;
4157        } else {
4158            write!(f, "ON {table_name} ")?;
4159            if let Some(p) = period {
4160                write!(f, "{p}")?;
4161            }
4162            if !events.is_empty() {
4163                write!(f, " {}", display_separated(events, ", "))?;
4164            }
4165        }
4166
4167        if let Some(referenced_table_name) = referenced_table_name {
4168            write!(f, " FROM {referenced_table_name}")?;
4169        }
4170
4171        if let Some(characteristics) = characteristics {
4172            write!(f, " {characteristics}")?;
4173        }
4174
4175        if !referencing.is_empty() {
4176            write!(f, " REFERENCING {}", display_separated(referencing, " "))?;
4177        }
4178
4179        if let Some(trigger_object) = trigger_object {
4180            write!(f, " {trigger_object}")?;
4181        }
4182        if let Some(condition) = condition {
4183            write!(f, " WHEN {condition}")?;
4184        }
4185        if let Some(exec_body) = exec_body {
4186            write!(f, " EXECUTE {exec_body}")?;
4187        }
4188        if let Some(statements) = statements {
4189            if *statements_as {
4190                write!(f, " AS")?;
4191            }
4192            write!(f, " {statements}")?;
4193        }
4194        Ok(())
4195    }
4196}
4197
4198#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4199#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4200#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4201/// DROP TRIGGER
4202///
4203/// ```sql
4204/// DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
4205/// ```
4206///
4207pub struct DropTrigger {
4208    /// Whether to include the `IF EXISTS` clause.
4209    pub if_exists: bool,
4210    /// The name of the trigger to be dropped.
4211    pub trigger_name: ObjectName,
4212    /// The name of the table from which the trigger is to be dropped.
4213    pub table_name: Option<ObjectName>,
4214    /// `CASCADE` or `RESTRICT`
4215    pub option: Option<ReferentialAction>,
4216}
4217
4218impl fmt::Display for DropTrigger {
4219    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4220        let DropTrigger {
4221            if_exists,
4222            trigger_name,
4223            table_name,
4224            option,
4225        } = self;
4226        write!(f, "DROP TRIGGER")?;
4227        if *if_exists {
4228            write!(f, " IF EXISTS")?;
4229        }
4230        match &table_name {
4231            Some(table_name) => write!(f, " {trigger_name} ON {table_name}")?,
4232            None => write!(f, " {trigger_name}")?,
4233        };
4234        if let Some(option) = option {
4235            write!(f, " {option}")?;
4236        }
4237        Ok(())
4238    }
4239}
4240
4241/// A `TRUNCATE` statement.
4242///
4243/// ```sql
4244/// TRUNCATE TABLE [IF EXISTS] table_names [PARTITION (partitions)] [RESTART IDENTITY | CONTINUE IDENTITY] [CASCADE | RESTRICT] [ON CLUSTER cluster_name]
4245/// ```
4246#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4247#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4248#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4249pub struct Truncate {
4250    /// Table names to truncate
4251    pub table_names: Vec<super::TruncateTableTarget>,
4252    /// Optional partition specification
4253    pub partitions: Option<Vec<Expr>>,
4254    /// TABLE - optional keyword
4255    pub table: bool,
4256    /// Snowflake/Redshift-specific option: [ IF EXISTS ]
4257    pub if_exists: bool,
4258    /// Postgres-specific option: [ RESTART IDENTITY | CONTINUE IDENTITY ]
4259    pub identity: Option<super::TruncateIdentityOption>,
4260    /// Postgres-specific option: [ CASCADE | RESTRICT ]
4261    pub cascade: Option<super::CascadeOption>,
4262    /// ClickHouse-specific option: [ ON CLUSTER cluster_name ]
4263    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/truncate/)
4264    pub on_cluster: Option<Ident>,
4265}
4266
4267impl fmt::Display for Truncate {
4268    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4269        let table = if self.table { "TABLE " } else { "" };
4270        let if_exists = if self.if_exists { "IF EXISTS " } else { "" };
4271
4272        write!(
4273            f,
4274            "TRUNCATE {table}{if_exists}{table_names}",
4275            table_names = display_comma_separated(&self.table_names)
4276        )?;
4277
4278        if let Some(identity) = &self.identity {
4279            match identity {
4280                super::TruncateIdentityOption::Restart => write!(f, " RESTART IDENTITY")?,
4281                super::TruncateIdentityOption::Continue => write!(f, " CONTINUE IDENTITY")?,
4282            }
4283        }
4284        if let Some(cascade) = &self.cascade {
4285            match cascade {
4286                super::CascadeOption::Cascade => write!(f, " CASCADE")?,
4287                super::CascadeOption::Restrict => write!(f, " RESTRICT")?,
4288            }
4289        }
4290
4291        if let Some(ref parts) = &self.partitions {
4292            if !parts.is_empty() {
4293                write!(f, " PARTITION ({})", display_comma_separated(parts))?;
4294            }
4295        }
4296        if let Some(on_cluster) = &self.on_cluster {
4297            write!(f, " ON CLUSTER {on_cluster}")?;
4298        }
4299        Ok(())
4300    }
4301}
4302
4303impl Spanned for Truncate {
4304    fn span(&self) -> Span {
4305        Span::union_iter(
4306            self.table_names.iter().map(|i| i.name.span()).chain(
4307                self.partitions
4308                    .iter()
4309                    .flat_map(|i| i.iter().map(|k| k.span())),
4310            ),
4311        )
4312    }
4313}
4314
4315/// An `MSCK` statement.
4316///
4317/// ```sql
4318/// MSCK [REPAIR] TABLE table_name [ADD|DROP|SYNC PARTITIONS]
4319/// ```
4320/// MSCK (Hive) - MetaStore Check command
4321#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4322#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4323#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4324pub struct Msck {
4325    /// Table name to check
4326    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
4327    pub table_name: ObjectName,
4328    /// Whether to repair the table
4329    pub repair: bool,
4330    /// Partition action (ADD, DROP, or SYNC)
4331    pub partition_action: Option<super::AddDropSync>,
4332}
4333
4334impl fmt::Display for Msck {
4335    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4336        write!(
4337            f,
4338            "MSCK {repair}TABLE {table}",
4339            repair = if self.repair { "REPAIR " } else { "" },
4340            table = self.table_name
4341        )?;
4342        if let Some(pa) = &self.partition_action {
4343            write!(f, " {pa}")?;
4344        }
4345        Ok(())
4346    }
4347}
4348
4349impl Spanned for Msck {
4350    fn span(&self) -> Span {
4351        self.table_name.span()
4352    }
4353}
4354
4355/// CREATE VIEW statement.
4356#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4357#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4358#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4359pub struct CreateView {
4360    /// True if this is a `CREATE OR ALTER VIEW` statement
4361    ///
4362    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-view-transact-sql)
4363    pub or_alter: bool,
4364    /// The `OR REPLACE` clause is used to re-create the view if it already exists.
4365    pub or_replace: bool,
4366    /// if true, has MATERIALIZED view modifier
4367    pub materialized: bool,
4368    /// Snowflake: SECURE view modifier
4369    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
4370    pub secure: bool,
4371    /// View name
4372    pub name: ObjectName,
4373    /// If `if_not_exists` is true, this flag is set to true if the view name comes before the `IF NOT EXISTS` clause.
4374    /// Example:
4375    /// ```sql
4376    /// CREATE VIEW myview IF NOT EXISTS AS SELECT 1`
4377    ///  ```
4378    /// Otherwise, the flag is set to false if the view name comes after the clause
4379    /// Example:
4380    /// ```sql
4381    /// CREATE VIEW IF NOT EXISTS myview AS SELECT 1`
4382    ///  ```
4383    pub name_before_not_exists: bool,
4384    /// Optional column definitions
4385    pub columns: Vec<ViewColumnDef>,
4386    /// The query that defines the view.
4387    pub query: Box<Query>,
4388    /// Table options (e.g., WITH (..), OPTIONS (...))
4389    pub options: CreateTableOptions,
4390    /// BigQuery: CLUSTER BY columns
4391    pub cluster_by: Vec<Ident>,
4392    /// Snowflake: Views can have comments in Snowflake.
4393    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
4394    pub comment: Option<String>,
4395    /// if true, has RedShift [`WITH NO SCHEMA BINDING`] clause <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_VIEW.html>
4396    pub with_no_schema_binding: bool,
4397    /// if true, has SQLite `IF NOT EXISTS` clause <https://www.sqlite.org/lang_createview.html>
4398    pub if_not_exists: bool,
4399    /// if true, has SQLite `TEMP` or `TEMPORARY` clause <https://www.sqlite.org/lang_createview.html>
4400    pub temporary: bool,
4401    /// Snowflake: `COPY GRANTS` clause
4402    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view>
4403    pub copy_grants: bool,
4404    /// if not None, has Clickhouse `TO` clause, specify the table into which to insert results
4405    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/view#materialized-view>
4406    pub to: Option<ObjectName>,
4407    /// MySQL: Optional parameters for the view algorithm, definer, and security context
4408    pub params: Option<CreateViewParams>,
4409    /// PostgreSQL: `WITH [NO] DATA` clause on materialized views.
4410    /// `None` means the clause was absent; `Some(true)` means `WITH DATA`;
4411    /// `Some(false)` means `WITH NO DATA`.
4412    /// <https://www.postgresql.org/docs/current/sql-creatematerializedview.html>
4413    pub with_data: Option<bool>,
4414}
4415
4416impl fmt::Display for CreateView {
4417    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4418        write!(
4419            f,
4420            "CREATE {or_alter}{or_replace}",
4421            or_alter = if self.or_alter { "OR ALTER " } else { "" },
4422            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
4423        )?;
4424        if let Some(ref params) = self.params {
4425            params.fmt(f)?;
4426        }
4427        write!(
4428            f,
4429            "{secure}{materialized}{temporary}VIEW {if_not_and_name}{to}",
4430            if_not_and_name = if self.if_not_exists {
4431                if self.name_before_not_exists {
4432                    format!("{} IF NOT EXISTS", self.name)
4433                } else {
4434                    format!("IF NOT EXISTS {}", self.name)
4435                }
4436            } else {
4437                format!("{}", self.name)
4438            },
4439            secure = if self.secure { "SECURE " } else { "" },
4440            materialized = if self.materialized {
4441                "MATERIALIZED "
4442            } else {
4443                ""
4444            },
4445            temporary = if self.temporary { "TEMPORARY " } else { "" },
4446            to = self
4447                .to
4448                .as_ref()
4449                .map(|to| format!(" TO {to}"))
4450                .unwrap_or_default()
4451        )?;
4452        if self.copy_grants {
4453            write!(f, " COPY GRANTS")?;
4454        }
4455        if !self.columns.is_empty() {
4456            write!(f, " ({})", display_comma_separated(&self.columns))?;
4457        }
4458        if matches!(self.options, CreateTableOptions::With(_)) {
4459            write!(f, " {}", self.options)?;
4460        }
4461        if let Some(ref comment) = self.comment {
4462            write!(f, " COMMENT = '{}'", escape_single_quote_string(comment))?;
4463        }
4464        if !self.cluster_by.is_empty() {
4465            write!(
4466                f,
4467                " CLUSTER BY ({})",
4468                display_comma_separated(&self.cluster_by)
4469            )?;
4470        }
4471        if matches!(self.options, CreateTableOptions::Options(_)) {
4472            write!(f, " {}", self.options)?;
4473        }
4474        f.write_str(" AS")?;
4475        SpaceOrNewline.fmt(f)?;
4476        self.query.fmt(f)?;
4477        if self.with_no_schema_binding {
4478            write!(f, " WITH NO SCHEMA BINDING")?;
4479        }
4480        match self.with_data {
4481            Some(true) => write!(f, " WITH DATA")?,
4482            Some(false) => write!(f, " WITH NO DATA")?,
4483            None => {}
4484        }
4485        Ok(())
4486    }
4487}
4488
4489/// CREATE EXTENSION statement
4490/// Note: this is a PostgreSQL-specific statement
4491#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4492#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4493#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4494pub struct CreateExtension {
4495    /// Extension name
4496    pub name: Ident,
4497    /// Whether `IF NOT EXISTS` was specified for the CREATE EXTENSION.
4498    pub if_not_exists: bool,
4499    /// Whether `CASCADE` was specified for the CREATE EXTENSION.
4500    pub cascade: bool,
4501    /// Optional schema name for the extension.
4502    pub schema: Option<Ident>,
4503    /// Optional version for the extension.
4504    pub version: Option<Ident>,
4505}
4506
4507impl fmt::Display for CreateExtension {
4508    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4509        write!(
4510            f,
4511            "CREATE EXTENSION {if_not_exists}{name}",
4512            if_not_exists = if self.if_not_exists {
4513                "IF NOT EXISTS "
4514            } else {
4515                ""
4516            },
4517            name = self.name
4518        )?;
4519        if self.cascade || self.schema.is_some() || self.version.is_some() {
4520            write!(f, " WITH")?;
4521
4522            if let Some(name) = &self.schema {
4523                write!(f, " SCHEMA {name}")?;
4524            }
4525            if let Some(version) = &self.version {
4526                write!(f, " VERSION {version}")?;
4527            }
4528            if self.cascade {
4529                write!(f, " CASCADE")?;
4530            }
4531        }
4532
4533        Ok(())
4534    }
4535}
4536
4537impl Spanned for CreateExtension {
4538    fn span(&self) -> Span {
4539        Span::empty()
4540    }
4541}
4542
4543/// DROP EXTENSION statement
4544/// Note: this is a PostgreSQL-specific statement
4545///
4546/// # References
4547///
4548/// PostgreSQL Documentation:
4549/// <https://www.postgresql.org/docs/current/sql-dropextension.html>
4550#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4551#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4552#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4553pub struct DropExtension {
4554    /// One or more extension names to drop
4555    pub names: Vec<Ident>,
4556    /// Whether `IF EXISTS` was specified for the DROP EXTENSION.
4557    pub if_exists: bool,
4558    /// `CASCADE` or `RESTRICT` behaviour for the drop.
4559    pub cascade_or_restrict: Option<ReferentialAction>,
4560}
4561
4562impl fmt::Display for DropExtension {
4563    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4564        write!(f, "DROP EXTENSION")?;
4565        if self.if_exists {
4566            write!(f, " IF EXISTS")?;
4567        }
4568        write!(f, " {}", display_comma_separated(&self.names))?;
4569        if let Some(cascade_or_restrict) = &self.cascade_or_restrict {
4570            write!(f, " {cascade_or_restrict}")?;
4571        }
4572        Ok(())
4573    }
4574}
4575
4576impl Spanned for DropExtension {
4577    fn span(&self) -> Span {
4578        Span::empty()
4579    }
4580}
4581
4582/// CREATE COLLATION statement.
4583/// Note: this is a PostgreSQL-specific statement.
4584#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4585#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4586#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4587pub struct CreateCollation {
4588    /// Whether `IF NOT EXISTS` was specified.
4589    pub if_not_exists: bool,
4590    /// Name of the collation being created.
4591    pub name: ObjectName,
4592    /// Source definition for the collation.
4593    pub definition: CreateCollationDefinition,
4594}
4595
4596/// Definition forms supported by `CREATE COLLATION`.
4597#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4598#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4599#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4600pub enum CreateCollationDefinition {
4601    /// Create from an existing collation.
4602    ///
4603    /// ```sql
4604    /// CREATE COLLATION name FROM existing_collation
4605    /// ```
4606    From(ObjectName),
4607    /// Create with an option list.
4608    ///
4609    /// ```sql
4610    /// CREATE COLLATION name (key = value, ...)
4611    /// ```
4612    Options(Vec<SqlOption>),
4613}
4614
4615impl fmt::Display for CreateCollation {
4616    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4617        write!(
4618            f,
4619            "CREATE COLLATION {if_not_exists}{name}",
4620            if_not_exists = if self.if_not_exists {
4621                "IF NOT EXISTS "
4622            } else {
4623                ""
4624            },
4625            name = self.name
4626        )?;
4627        match &self.definition {
4628            CreateCollationDefinition::From(existing_collation) => {
4629                write!(f, " FROM {existing_collation}")
4630            }
4631            CreateCollationDefinition::Options(options) => {
4632                write!(f, " ({})", display_comma_separated(options))
4633            }
4634        }
4635    }
4636}
4637
4638impl Spanned for CreateCollation {
4639    fn span(&self) -> Span {
4640        Span::empty()
4641    }
4642}
4643
4644/// ALTER COLLATION statement.
4645/// Note: this is a PostgreSQL-specific statement.
4646#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4647#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4648#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4649pub struct AlterCollation {
4650    /// Name of the collation being altered.
4651    pub name: ObjectName,
4652    /// The operation to perform on the collation.
4653    pub operation: AlterCollationOperation,
4654}
4655
4656/// Operations supported by `ALTER COLLATION`.
4657#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4658#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4659#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4660pub enum AlterCollationOperation {
4661    /// Rename the collation.
4662    ///
4663    /// ```sql
4664    /// ALTER COLLATION name RENAME TO new_name
4665    /// ```
4666    RenameTo {
4667        /// New collation name.
4668        new_name: Ident,
4669    },
4670    /// Change the collation owner.
4671    ///
4672    /// ```sql
4673    /// ALTER COLLATION name OWNER TO role_name
4674    /// ```
4675    OwnerTo(Owner),
4676    /// Move the collation to another schema.
4677    ///
4678    /// ```sql
4679    /// ALTER COLLATION name SET SCHEMA new_schema
4680    /// ```
4681    SetSchema {
4682        /// Target schema name.
4683        schema_name: ObjectName,
4684    },
4685    /// Refresh collation version metadata.
4686    ///
4687    /// ```sql
4688    /// ALTER COLLATION name REFRESH VERSION
4689    /// ```
4690    RefreshVersion,
4691}
4692
4693impl fmt::Display for AlterCollationOperation {
4694    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4695        match self {
4696            AlterCollationOperation::RenameTo { new_name } => write!(f, "RENAME TO {new_name}"),
4697            AlterCollationOperation::OwnerTo(owner) => write!(f, "OWNER TO {owner}"),
4698            AlterCollationOperation::SetSchema { schema_name } => {
4699                write!(f, "SET SCHEMA {schema_name}")
4700            }
4701            AlterCollationOperation::RefreshVersion => write!(f, "REFRESH VERSION"),
4702        }
4703    }
4704}
4705
4706impl fmt::Display for AlterCollation {
4707    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4708        write!(f, "ALTER COLLATION {} {}", self.name, self.operation)
4709    }
4710}
4711
4712impl Spanned for AlterCollation {
4713    fn span(&self) -> Span {
4714        Span::empty()
4715    }
4716}
4717
4718/// Table type for ALTER TABLE statements.
4719/// Used to distinguish between regular tables, Iceberg tables, and Dynamic tables.
4720#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4721#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4722#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4723pub enum AlterTableType {
4724    /// Iceberg table type
4725    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
4726    Iceberg,
4727    /// Dynamic table type
4728    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-dynamic-table>
4729    Dynamic,
4730    /// External table type
4731    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
4732    External,
4733}
4734
4735/// ALTER TABLE statement
4736#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4737#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4738#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4739pub struct AlterTable {
4740    /// Table name
4741    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
4742    pub name: ObjectName,
4743    /// Whether `IF EXISTS` was specified for the `ALTER TABLE`.
4744    pub if_exists: bool,
4745    /// Whether the `ONLY` keyword was used (restrict scope to the named table).
4746    pub only: bool,
4747    /// List of `ALTER TABLE` operations to apply.
4748    pub operations: Vec<AlterTableOperation>,
4749    /// Optional Hive `SET LOCATION` clause for the alter operation.
4750    pub location: Option<HiveSetLocation>,
4751    /// ClickHouse dialect supports `ON CLUSTER` clause for ALTER TABLE
4752    /// For example: `ALTER TABLE table_name ON CLUSTER cluster_name ADD COLUMN c UInt32`
4753    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/update)
4754    pub on_cluster: Option<Ident>,
4755    /// Table type: None for regular tables, Some(AlterTableType) for Iceberg or Dynamic tables
4756    pub table_type: Option<AlterTableType>,
4757    /// Token that represents the end of the statement (semicolon or EOF)
4758    pub end_token: AttachedToken,
4759}
4760
4761impl fmt::Display for AlterTable {
4762    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4763        match &self.table_type {
4764            Some(AlterTableType::Iceberg) => write!(f, "ALTER ICEBERG TABLE ")?,
4765            Some(AlterTableType::Dynamic) => write!(f, "ALTER DYNAMIC TABLE ")?,
4766            Some(AlterTableType::External) => write!(f, "ALTER EXTERNAL TABLE ")?,
4767            None => write!(f, "ALTER TABLE ")?,
4768        }
4769
4770        if self.if_exists {
4771            write!(f, "IF EXISTS ")?;
4772        }
4773        if self.only {
4774            write!(f, "ONLY ")?;
4775        }
4776        write!(f, "{} ", &self.name)?;
4777        if let Some(cluster) = &self.on_cluster {
4778            write!(f, "ON CLUSTER {cluster} ")?;
4779        }
4780        write!(f, "{}", display_comma_separated(&self.operations))?;
4781        if let Some(loc) = &self.location {
4782            write!(f, " {loc}")?
4783        }
4784        Ok(())
4785    }
4786}
4787
4788/// DROP FUNCTION statement
4789#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4790#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4791#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4792pub struct DropFunction {
4793    /// Whether to include the `IF EXISTS` clause.
4794    pub if_exists: bool,
4795    /// One or more functions to drop
4796    pub func_desc: Vec<FunctionDesc>,
4797    /// `CASCADE` or `RESTRICT`
4798    pub drop_behavior: Option<DropBehavior>,
4799}
4800
4801impl fmt::Display for DropFunction {
4802    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4803        write!(
4804            f,
4805            "DROP FUNCTION{} {}",
4806            if self.if_exists { " IF EXISTS" } else { "" },
4807            display_comma_separated(&self.func_desc),
4808        )?;
4809        if let Some(op) = &self.drop_behavior {
4810            write!(f, " {op}")?;
4811        }
4812        Ok(())
4813    }
4814}
4815
4816impl Spanned for DropFunction {
4817    fn span(&self) -> Span {
4818        Span::empty()
4819    }
4820}
4821
4822/// CREATE OPERATOR statement
4823/// See <https://www.postgresql.org/docs/current/sql-createoperator.html>
4824#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4825#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4826#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4827pub struct CreateOperator {
4828    /// Operator name (can be schema-qualified)
4829    pub name: ObjectName,
4830    /// FUNCTION or PROCEDURE parameter (function name)
4831    pub function: ObjectName,
4832    /// Whether PROCEDURE keyword was used (vs FUNCTION)
4833    pub is_procedure: bool,
4834    /// LEFTARG parameter (left operand type)
4835    pub left_arg: Option<DataType>,
4836    /// RIGHTARG parameter (right operand type)
4837    pub right_arg: Option<DataType>,
4838    /// Operator options (COMMUTATOR, NEGATOR, RESTRICT, JOIN, HASHES, MERGES)
4839    pub options: Vec<OperatorOption>,
4840}
4841
4842/// CREATE OPERATOR FAMILY statement
4843/// See <https://www.postgresql.org/docs/current/sql-createopfamily.html>
4844#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4845#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4846#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4847pub struct CreateOperatorFamily {
4848    /// Operator family name (can be schema-qualified)
4849    pub name: ObjectName,
4850    /// Index method (btree, hash, gist, gin, etc.)
4851    pub using: Ident,
4852}
4853
4854/// CREATE OPERATOR CLASS statement
4855/// See <https://www.postgresql.org/docs/current/sql-createopclass.html>
4856#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4857#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4858#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4859pub struct CreateOperatorClass {
4860    /// Operator class name (can be schema-qualified)
4861    pub name: ObjectName,
4862    /// Whether this is the default operator class for the type
4863    pub default: bool,
4864    /// The data type
4865    pub for_type: DataType,
4866    /// Index method (btree, hash, gist, gin, etc.)
4867    pub using: Ident,
4868    /// Optional operator family name
4869    pub family: Option<ObjectName>,
4870    /// List of operator class items (operators, functions, storage)
4871    pub items: Vec<OperatorClassItem>,
4872}
4873
4874impl fmt::Display for CreateOperator {
4875    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4876        write!(f, "CREATE OPERATOR {} (", self.name)?;
4877
4878        let function_keyword = if self.is_procedure {
4879            "PROCEDURE"
4880        } else {
4881            "FUNCTION"
4882        };
4883        let mut params = vec![format!("{} = {}", function_keyword, self.function)];
4884
4885        if let Some(left_arg) = &self.left_arg {
4886            params.push(format!("LEFTARG = {}", left_arg));
4887        }
4888        if let Some(right_arg) = &self.right_arg {
4889            params.push(format!("RIGHTARG = {}", right_arg));
4890        }
4891
4892        for option in &self.options {
4893            params.push(option.to_string());
4894        }
4895
4896        write!(f, "{}", params.join(", "))?;
4897        write!(f, ")")
4898    }
4899}
4900
4901impl fmt::Display for CreateOperatorFamily {
4902    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4903        write!(
4904            f,
4905            "CREATE OPERATOR FAMILY {} USING {}",
4906            self.name, self.using
4907        )
4908    }
4909}
4910
4911impl fmt::Display for CreateOperatorClass {
4912    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4913        write!(f, "CREATE OPERATOR CLASS {}", self.name)?;
4914        if self.default {
4915            write!(f, " DEFAULT")?;
4916        }
4917        write!(f, " FOR TYPE {} USING {}", self.for_type, self.using)?;
4918        if let Some(family) = &self.family {
4919            write!(f, " FAMILY {}", family)?;
4920        }
4921        write!(f, " AS {}", display_comma_separated(&self.items))
4922    }
4923}
4924
4925/// Operator argument types for CREATE OPERATOR CLASS
4926#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4927#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4928#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4929pub struct OperatorArgTypes {
4930    /// Left-hand operand data type for the operator.
4931    pub left: DataType,
4932    /// Right-hand operand data type for the operator.
4933    pub right: DataType,
4934}
4935
4936impl fmt::Display for OperatorArgTypes {
4937    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4938        write!(f, "{}, {}", self.left, self.right)
4939    }
4940}
4941
4942/// An item in a CREATE OPERATOR CLASS statement
4943#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4944#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4945#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4946pub enum OperatorClassItem {
4947    /// `OPERATOR` clause describing a specific operator implementation.
4948    Operator {
4949        /// Strategy number identifying the operator position in the opclass.
4950        strategy_number: u64,
4951        /// The operator name referenced by this clause.
4952        operator_name: ObjectName,
4953        /// Optional operator argument types.
4954        op_types: Option<OperatorArgTypes>,
4955        /// Optional purpose such as `FOR SEARCH` or `FOR ORDER BY`.
4956        purpose: Option<OperatorPurpose>,
4957    },
4958    /// `FUNCTION` clause describing a support function for the operator class.
4959    Function {
4960        /// Support function number for this entry.
4961        support_number: u64,
4962        /// Optional function argument types for the operator class.
4963        op_types: Option<Vec<DataType>>,
4964        /// The function name implementing the support function.
4965        function_name: ObjectName,
4966        /// Function argument types for the support function.
4967        argument_types: Vec<DataType>,
4968    },
4969    /// `STORAGE` clause specifying the storage type.
4970    Storage {
4971        /// The storage data type.
4972        storage_type: DataType,
4973    },
4974}
4975
4976/// Purpose of an operator in an operator class
4977#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4978#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4979#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4980pub enum OperatorPurpose {
4981    /// Purpose: used for index/search operations.
4982    ForSearch,
4983    /// Purpose: used for ORDER BY; optionally includes a sort family name.
4984    ForOrderBy {
4985        /// Optional sort family object name.
4986        sort_family: ObjectName,
4987    },
4988}
4989
4990impl fmt::Display for OperatorClassItem {
4991    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4992        match self {
4993            OperatorClassItem::Operator {
4994                strategy_number,
4995                operator_name,
4996                op_types,
4997                purpose,
4998            } => {
4999                write!(f, "OPERATOR {strategy_number} {operator_name}")?;
5000                if let Some(types) = op_types {
5001                    write!(f, " ({types})")?;
5002                }
5003                if let Some(purpose) = purpose {
5004                    write!(f, " {purpose}")?;
5005                }
5006                Ok(())
5007            }
5008            OperatorClassItem::Function {
5009                support_number,
5010                op_types,
5011                function_name,
5012                argument_types,
5013            } => {
5014                write!(f, "FUNCTION {support_number}")?;
5015                if let Some(types) = op_types {
5016                    write!(f, " ({})", display_comma_separated(types))?;
5017                }
5018                write!(f, " {function_name}")?;
5019                if !argument_types.is_empty() {
5020                    write!(f, "({})", display_comma_separated(argument_types))?;
5021                }
5022                Ok(())
5023            }
5024            OperatorClassItem::Storage { storage_type } => {
5025                write!(f, "STORAGE {storage_type}")
5026            }
5027        }
5028    }
5029}
5030
5031impl fmt::Display for OperatorPurpose {
5032    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5033        match self {
5034            OperatorPurpose::ForSearch => write!(f, "FOR SEARCH"),
5035            OperatorPurpose::ForOrderBy { sort_family } => {
5036                write!(f, "FOR ORDER BY {sort_family}")
5037            }
5038        }
5039    }
5040}
5041
5042/// `DROP OPERATOR` statement
5043/// See <https://www.postgresql.org/docs/current/sql-dropoperator.html>
5044#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5045#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5046#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5047pub struct DropOperator {
5048    /// `IF EXISTS` clause
5049    pub if_exists: bool,
5050    /// One or more operators to drop with their signatures
5051    pub operators: Vec<DropOperatorSignature>,
5052    /// `CASCADE or RESTRICT`
5053    pub drop_behavior: Option<DropBehavior>,
5054}
5055
5056/// Operator signature for a `DROP OPERATOR` statement
5057#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5058#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5059#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5060pub struct DropOperatorSignature {
5061    /// Operator name
5062    pub name: ObjectName,
5063    /// Left operand type
5064    pub left_type: Option<DataType>,
5065    /// Right operand type
5066    pub right_type: DataType,
5067}
5068
5069impl fmt::Display for DropOperatorSignature {
5070    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5071        write!(f, "{} (", self.name)?;
5072        if let Some(left_type) = &self.left_type {
5073            write!(f, "{}", left_type)?;
5074        } else {
5075            write!(f, "NONE")?;
5076        }
5077        write!(f, ", {})", self.right_type)
5078    }
5079}
5080
5081impl fmt::Display for DropOperator {
5082    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5083        write!(f, "DROP OPERATOR")?;
5084        if self.if_exists {
5085            write!(f, " IF EXISTS")?;
5086        }
5087        write!(f, " {}", display_comma_separated(&self.operators))?;
5088        if let Some(drop_behavior) = &self.drop_behavior {
5089            write!(f, " {}", drop_behavior)?;
5090        }
5091        Ok(())
5092    }
5093}
5094
5095impl Spanned for DropOperator {
5096    fn span(&self) -> Span {
5097        Span::empty()
5098    }
5099}
5100
5101/// `DROP OPERATOR FAMILY` statement
5102/// See <https://www.postgresql.org/docs/current/sql-dropopfamily.html>
5103#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5104#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5105#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5106pub struct DropOperatorFamily {
5107    /// `IF EXISTS` clause
5108    pub if_exists: bool,
5109    /// One or more operator families to drop
5110    pub names: Vec<ObjectName>,
5111    /// Index method (btree, hash, gist, gin, etc.)
5112    pub using: Ident,
5113    /// `CASCADE or RESTRICT`
5114    pub drop_behavior: Option<DropBehavior>,
5115}
5116
5117impl fmt::Display for DropOperatorFamily {
5118    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5119        write!(f, "DROP OPERATOR FAMILY")?;
5120        if self.if_exists {
5121            write!(f, " IF EXISTS")?;
5122        }
5123        write!(f, " {}", display_comma_separated(&self.names))?;
5124        write!(f, " USING {}", self.using)?;
5125        if let Some(drop_behavior) = &self.drop_behavior {
5126            write!(f, " {}", drop_behavior)?;
5127        }
5128        Ok(())
5129    }
5130}
5131
5132impl Spanned for DropOperatorFamily {
5133    fn span(&self) -> Span {
5134        Span::empty()
5135    }
5136}
5137
5138/// `DROP OPERATOR CLASS` statement
5139/// See <https://www.postgresql.org/docs/current/sql-dropopclass.html>
5140#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5141#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5142#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5143pub struct DropOperatorClass {
5144    /// `IF EXISTS` clause
5145    pub if_exists: bool,
5146    /// One or more operator classes to drop
5147    pub names: Vec<ObjectName>,
5148    /// Index method (btree, hash, gist, gin, etc.)
5149    pub using: Ident,
5150    /// `CASCADE or RESTRICT`
5151    pub drop_behavior: Option<DropBehavior>,
5152}
5153
5154impl fmt::Display for DropOperatorClass {
5155    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5156        write!(f, "DROP OPERATOR CLASS")?;
5157        if self.if_exists {
5158            write!(f, " IF EXISTS")?;
5159        }
5160        write!(f, " {}", display_comma_separated(&self.names))?;
5161        write!(f, " USING {}", self.using)?;
5162        if let Some(drop_behavior) = &self.drop_behavior {
5163            write!(f, " {}", drop_behavior)?;
5164        }
5165        Ok(())
5166    }
5167}
5168
5169impl Spanned for DropOperatorClass {
5170    fn span(&self) -> Span {
5171        Span::empty()
5172    }
5173}
5174
5175/// An item in an ALTER OPERATOR FAMILY ADD statement
5176#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5177#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5178#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5179pub enum OperatorFamilyItem {
5180    /// `OPERATOR` clause in an operator family modification.
5181    Operator {
5182        /// Strategy number for the operator.
5183        strategy_number: u64,
5184        /// Operator name referenced by this entry.
5185        operator_name: ObjectName,
5186        /// Operator argument types.
5187        op_types: Vec<DataType>,
5188        /// Optional purpose such as `FOR SEARCH` or `FOR ORDER BY`.
5189        purpose: Option<OperatorPurpose>,
5190    },
5191    /// `FUNCTION` clause in an operator family modification.
5192    Function {
5193        /// Support function number.
5194        support_number: u64,
5195        /// Optional operator argument types for the function.
5196        op_types: Option<Vec<DataType>>,
5197        /// Function name for the support function.
5198        function_name: ObjectName,
5199        /// Function argument types.
5200        argument_types: Vec<DataType>,
5201    },
5202}
5203
5204/// An item in an ALTER OPERATOR FAMILY DROP statement
5205#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5206#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5207#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5208pub enum OperatorFamilyDropItem {
5209    /// `OPERATOR` clause for DROP within an operator family.
5210    Operator {
5211        /// Strategy number for the operator.
5212        strategy_number: u64,
5213        /// Operator argument types.
5214        op_types: Vec<DataType>,
5215    },
5216    /// `FUNCTION` clause for DROP within an operator family.
5217    Function {
5218        /// Support function number.
5219        support_number: u64,
5220        /// Operator argument types for the function.
5221        op_types: Vec<DataType>,
5222    },
5223}
5224
5225impl fmt::Display for OperatorFamilyItem {
5226    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5227        match self {
5228            OperatorFamilyItem::Operator {
5229                strategy_number,
5230                operator_name,
5231                op_types,
5232                purpose,
5233            } => {
5234                write!(
5235                    f,
5236                    "OPERATOR {strategy_number} {operator_name} ({})",
5237                    display_comma_separated(op_types)
5238                )?;
5239                if let Some(purpose) = purpose {
5240                    write!(f, " {purpose}")?;
5241                }
5242                Ok(())
5243            }
5244            OperatorFamilyItem::Function {
5245                support_number,
5246                op_types,
5247                function_name,
5248                argument_types,
5249            } => {
5250                write!(f, "FUNCTION {support_number}")?;
5251                if let Some(types) = op_types {
5252                    write!(f, " ({})", display_comma_separated(types))?;
5253                }
5254                write!(f, " {function_name}")?;
5255                if !argument_types.is_empty() {
5256                    write!(f, "({})", display_comma_separated(argument_types))?;
5257                }
5258                Ok(())
5259            }
5260        }
5261    }
5262}
5263
5264impl fmt::Display for OperatorFamilyDropItem {
5265    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5266        match self {
5267            OperatorFamilyDropItem::Operator {
5268                strategy_number,
5269                op_types,
5270            } => {
5271                write!(
5272                    f,
5273                    "OPERATOR {strategy_number} ({})",
5274                    display_comma_separated(op_types)
5275                )
5276            }
5277            OperatorFamilyDropItem::Function {
5278                support_number,
5279                op_types,
5280            } => {
5281                write!(
5282                    f,
5283                    "FUNCTION {support_number} ({})",
5284                    display_comma_separated(op_types)
5285                )
5286            }
5287        }
5288    }
5289}
5290
5291/// `ALTER OPERATOR FAMILY` statement
5292/// See <https://www.postgresql.org/docs/current/sql-alteropfamily.html>
5293#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5294#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5295#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5296pub struct AlterOperatorFamily {
5297    /// Operator family name (can be schema-qualified)
5298    pub name: ObjectName,
5299    /// Index method (btree, hash, gist, gin, etc.)
5300    pub using: Ident,
5301    /// The operation to perform
5302    pub operation: AlterOperatorFamilyOperation,
5303}
5304
5305/// An [AlterOperatorFamily] operation
5306#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5307#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5308#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5309pub enum AlterOperatorFamilyOperation {
5310    /// `ADD { OPERATOR ... | FUNCTION ... } [, ...]`
5311    Add {
5312        /// List of operator family items to add
5313        items: Vec<OperatorFamilyItem>,
5314    },
5315    /// `DROP { OPERATOR ... | FUNCTION ... } [, ...]`
5316    Drop {
5317        /// List of operator family items to drop
5318        items: Vec<OperatorFamilyDropItem>,
5319    },
5320    /// `RENAME TO new_name`
5321    RenameTo {
5322        /// The new name for the operator family.
5323        new_name: ObjectName,
5324    },
5325    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
5326    OwnerTo(Owner),
5327    /// `SET SCHEMA new_schema`
5328    SetSchema {
5329        /// The target schema name.
5330        schema_name: ObjectName,
5331    },
5332}
5333
5334impl fmt::Display for AlterOperatorFamily {
5335    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5336        write!(
5337            f,
5338            "ALTER OPERATOR FAMILY {} USING {}",
5339            self.name, self.using
5340        )?;
5341        write!(f, " {}", self.operation)
5342    }
5343}
5344
5345impl fmt::Display for AlterOperatorFamilyOperation {
5346    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5347        match self {
5348            AlterOperatorFamilyOperation::Add { items } => {
5349                write!(f, "ADD {}", display_comma_separated(items))
5350            }
5351            AlterOperatorFamilyOperation::Drop { items } => {
5352                write!(f, "DROP {}", display_comma_separated(items))
5353            }
5354            AlterOperatorFamilyOperation::RenameTo { new_name } => {
5355                write!(f, "RENAME TO {new_name}")
5356            }
5357            AlterOperatorFamilyOperation::OwnerTo(owner) => {
5358                write!(f, "OWNER TO {owner}")
5359            }
5360            AlterOperatorFamilyOperation::SetSchema { schema_name } => {
5361                write!(f, "SET SCHEMA {schema_name}")
5362            }
5363        }
5364    }
5365}
5366
5367impl Spanned for AlterOperatorFamily {
5368    fn span(&self) -> Span {
5369        Span::empty()
5370    }
5371}
5372
5373/// `ALTER OPERATOR CLASS` statement
5374/// See <https://www.postgresql.org/docs/current/sql-alteropclass.html>
5375#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5376#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5377#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5378pub struct AlterOperatorClass {
5379    /// Operator class name (can be schema-qualified)
5380    pub name: ObjectName,
5381    /// Index method (btree, hash, gist, gin, etc.)
5382    pub using: Ident,
5383    /// The operation to perform
5384    pub operation: AlterOperatorClassOperation,
5385}
5386
5387/// An [AlterOperatorClass] operation
5388#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5389#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5390#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5391pub enum AlterOperatorClassOperation {
5392    /// `RENAME TO new_name`
5393    /// Rename the operator class to a new name.
5394    RenameTo {
5395        /// The new name for the operator class.
5396        new_name: ObjectName,
5397    },
5398    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
5399    OwnerTo(Owner),
5400    /// `SET SCHEMA new_schema`
5401    /// Set the schema for the operator class.
5402    SetSchema {
5403        /// The target schema name.
5404        schema_name: ObjectName,
5405    },
5406}
5407
5408impl fmt::Display for AlterOperatorClass {
5409    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5410        write!(f, "ALTER OPERATOR CLASS {} USING {}", self.name, self.using)?;
5411        write!(f, " {}", self.operation)
5412    }
5413}
5414
5415impl fmt::Display for AlterOperatorClassOperation {
5416    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5417        match self {
5418            AlterOperatorClassOperation::RenameTo { new_name } => {
5419                write!(f, "RENAME TO {new_name}")
5420            }
5421            AlterOperatorClassOperation::OwnerTo(owner) => {
5422                write!(f, "OWNER TO {owner}")
5423            }
5424            AlterOperatorClassOperation::SetSchema { schema_name } => {
5425                write!(f, "SET SCHEMA {schema_name}")
5426            }
5427        }
5428    }
5429}
5430
5431impl Spanned for AlterOperatorClass {
5432    fn span(&self) -> Span {
5433        Span::empty()
5434    }
5435}
5436
5437/// `ALTER FUNCTION` / `ALTER AGGREGATE` statement.
5438#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5439#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5440#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5441pub struct AlterFunction {
5442    /// Object type being altered.
5443    pub kind: AlterFunctionKind,
5444    /// Function or aggregate signature.
5445    pub function: FunctionDesc,
5446    /// `ORDER BY` argument list for aggregate signatures.
5447    ///
5448    /// This is only used for `ALTER AGGREGATE`.
5449    pub aggregate_order_by: Option<Vec<OperateFunctionArg>>,
5450    /// Whether the aggregate signature uses `*`.
5451    ///
5452    /// This is only used for `ALTER AGGREGATE`.
5453    pub aggregate_star: bool,
5454    /// Operation applied to the object.
5455    pub operation: AlterFunctionOperation,
5456}
5457
5458/// Function-like object type used by [`AlterFunction`].
5459#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5460#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5461#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5462pub enum AlterFunctionKind {
5463    /// `FUNCTION`
5464    Function,
5465    /// `AGGREGATE`
5466    Aggregate,
5467    /// `PROCEDURE`
5468    Procedure,
5469}
5470
5471impl fmt::Display for AlterFunctionKind {
5472    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5473        match self {
5474            Self::Function => write!(f, "FUNCTION"),
5475            Self::Aggregate => write!(f, "AGGREGATE"),
5476            Self::Procedure => write!(f, "PROCEDURE"),
5477        }
5478    }
5479}
5480
5481/// Operation for `ALTER FUNCTION` / `ALTER AGGREGATE`.
5482#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5483#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5484#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5485pub enum AlterFunctionOperation {
5486    /// `RENAME TO new_name`
5487    RenameTo {
5488        /// New unqualified function or aggregate name.
5489        new_name: Ident,
5490    },
5491    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
5492    OwnerTo(Owner),
5493    /// `SET SCHEMA schema_name`
5494    SetSchema {
5495        /// The target schema name.
5496        schema_name: ObjectName,
5497    },
5498    /// `[ NO ] DEPENDS ON EXTENSION extension_name`
5499    DependsOnExtension {
5500        /// `true` when `NO DEPENDS ON EXTENSION`.
5501        no: bool,
5502        /// Extension name.
5503        extension_name: ObjectName,
5504    },
5505    /// `action [ ... ] [ RESTRICT ]` (function only).
5506    Actions {
5507        /// One or more function actions.
5508        actions: Vec<AlterFunctionAction>,
5509        /// Whether `RESTRICT` is present.
5510        restrict: bool,
5511    },
5512}
5513
5514/// Function action in `ALTER FUNCTION ... action [ ... ] [ RESTRICT ]`.
5515#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5516#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5517#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5518pub enum AlterFunctionAction {
5519    /// `CALLED ON NULL INPUT` / `RETURNS NULL ON NULL INPUT` / `STRICT`
5520    CalledOnNull(FunctionCalledOnNull),
5521    /// `IMMUTABLE` / `STABLE` / `VOLATILE`
5522    Behavior(FunctionBehavior),
5523    /// `[ NOT ] LEAKPROOF`
5524    Leakproof(bool),
5525    /// `[ EXTERNAL ] SECURITY { DEFINER | INVOKER }`
5526    Security {
5527        /// Whether the optional `EXTERNAL` keyword was present.
5528        external: bool,
5529        /// Security mode.
5530        security: FunctionSecurity,
5531    },
5532    /// `PARALLEL { UNSAFE | RESTRICTED | SAFE }`
5533    Parallel(FunctionParallel),
5534    /// `COST execution_cost`
5535    Cost(Expr),
5536    /// `ROWS result_rows`
5537    Rows(Expr),
5538    /// `SUPPORT support_function`
5539    Support(ObjectName),
5540    /// `SET configuration_parameter { TO | = } { value | DEFAULT }`
5541    /// or `SET configuration_parameter FROM CURRENT`
5542    Set(FunctionDefinitionSetParam),
5543    /// `RESET configuration_parameter` or `RESET ALL`
5544    Reset(ResetConfig),
5545}
5546
5547impl fmt::Display for AlterFunction {
5548    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5549        write!(f, "ALTER {} ", self.kind)?;
5550        match self.kind {
5551            AlterFunctionKind::Function | AlterFunctionKind::Procedure => {
5552                write!(f, "{} ", self.function)?;
5553            }
5554            AlterFunctionKind::Aggregate => {
5555                write!(f, "{}(", self.function.name)?;
5556                if self.aggregate_star {
5557                    write!(f, "*")?;
5558                } else {
5559                    if let Some(args) = &self.function.args {
5560                        write!(f, "{}", display_comma_separated(args))?;
5561                    }
5562                    if let Some(order_by_args) = &self.aggregate_order_by {
5563                        if self
5564                            .function
5565                            .args
5566                            .as_ref()
5567                            .is_some_and(|args| !args.is_empty())
5568                        {
5569                            write!(f, " ")?;
5570                        }
5571                        write!(f, "ORDER BY {}", display_comma_separated(order_by_args))?;
5572                    }
5573                }
5574                write!(f, ") ")?;
5575            }
5576        }
5577        write!(f, "{}", self.operation)
5578    }
5579}
5580
5581impl fmt::Display for AlterFunctionOperation {
5582    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5583        match self {
5584            AlterFunctionOperation::RenameTo { new_name } => {
5585                write!(f, "RENAME TO {new_name}")
5586            }
5587            AlterFunctionOperation::OwnerTo(owner) => write!(f, "OWNER TO {owner}"),
5588            AlterFunctionOperation::SetSchema { schema_name } => {
5589                write!(f, "SET SCHEMA {schema_name}")
5590            }
5591            AlterFunctionOperation::DependsOnExtension { no, extension_name } => {
5592                if *no {
5593                    write!(f, "NO DEPENDS ON EXTENSION {extension_name}")
5594                } else {
5595                    write!(f, "DEPENDS ON EXTENSION {extension_name}")
5596                }
5597            }
5598            AlterFunctionOperation::Actions { actions, restrict } => {
5599                write!(f, "{}", display_separated(actions, " "))?;
5600                if *restrict {
5601                    write!(f, " RESTRICT")?;
5602                }
5603                Ok(())
5604            }
5605        }
5606    }
5607}
5608
5609impl fmt::Display for AlterFunctionAction {
5610    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5611        match self {
5612            AlterFunctionAction::CalledOnNull(called_on_null) => write!(f, "{called_on_null}"),
5613            AlterFunctionAction::Behavior(behavior) => write!(f, "{behavior}"),
5614            AlterFunctionAction::Leakproof(leakproof) => {
5615                if *leakproof {
5616                    write!(f, "LEAKPROOF")
5617                } else {
5618                    write!(f, "NOT LEAKPROOF")
5619                }
5620            }
5621            AlterFunctionAction::Security { external, security } => {
5622                if *external {
5623                    write!(f, "EXTERNAL ")?;
5624                }
5625                write!(f, "{security}")
5626            }
5627            AlterFunctionAction::Parallel(parallel) => write!(f, "{parallel}"),
5628            AlterFunctionAction::Cost(execution_cost) => write!(f, "COST {execution_cost}"),
5629            AlterFunctionAction::Rows(result_rows) => write!(f, "ROWS {result_rows}"),
5630            AlterFunctionAction::Support(support_function) => {
5631                write!(f, "SUPPORT {support_function}")
5632            }
5633            AlterFunctionAction::Set(set_param) => write!(f, "{set_param}"),
5634            AlterFunctionAction::Reset(reset_config) => match reset_config {
5635                ResetConfig::ALL => write!(f, "RESET ALL"),
5636                ResetConfig::ConfigName(name) => write!(f, "RESET {name}"),
5637            },
5638        }
5639    }
5640}
5641
5642impl Spanned for AlterFunction {
5643    fn span(&self) -> Span {
5644        Span::empty()
5645    }
5646}
5647
5648/// CREATE POLICY statement.
5649///
5650/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createpolicy.html)
5651#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5652#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5653#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5654pub struct CreatePolicy {
5655    /// Name of the policy.
5656    pub name: Ident,
5657    /// Table the policy is defined on.
5658    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
5659    pub table_name: ObjectName,
5660    /// Optional policy type (e.g., `PERMISSIVE` / `RESTRICTIVE`).
5661    pub policy_type: Option<CreatePolicyType>,
5662    /// Optional command the policy applies to (e.g., `SELECT`).
5663    pub command: Option<CreatePolicyCommand>,
5664    /// Optional list of grantee owners.
5665    pub to: Option<Vec<Owner>>,
5666    /// Optional expression for the `USING` clause.
5667    pub using: Option<Expr>,
5668    /// Optional expression for the `WITH CHECK` clause.
5669    pub with_check: Option<Expr>,
5670}
5671
5672impl fmt::Display for CreatePolicy {
5673    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5674        write!(
5675            f,
5676            "CREATE POLICY {name} ON {table_name}",
5677            name = self.name,
5678            table_name = self.table_name,
5679        )?;
5680        if let Some(ref policy_type) = self.policy_type {
5681            write!(f, " AS {policy_type}")?;
5682        }
5683        if let Some(ref command) = self.command {
5684            write!(f, " FOR {command}")?;
5685        }
5686        if let Some(ref to) = self.to {
5687            write!(f, " TO {}", display_comma_separated(to))?;
5688        }
5689        if let Some(ref using) = self.using {
5690            write!(f, " USING ({using})")?;
5691        }
5692        if let Some(ref with_check) = self.with_check {
5693            write!(f, " WITH CHECK ({with_check})")?;
5694        }
5695        Ok(())
5696    }
5697}
5698
5699/// Policy type for a `CREATE POLICY` statement.
5700/// ```sql
5701/// AS [ PERMISSIVE | RESTRICTIVE ]
5702/// ```
5703/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createpolicy.html)
5704#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
5705#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5706#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5707pub enum CreatePolicyType {
5708    /// Policy allows operations unless explicitly denied.
5709    Permissive,
5710    /// Policy denies operations unless explicitly allowed.
5711    Restrictive,
5712}
5713
5714impl fmt::Display for CreatePolicyType {
5715    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5716        match self {
5717            CreatePolicyType::Permissive => write!(f, "PERMISSIVE"),
5718            CreatePolicyType::Restrictive => write!(f, "RESTRICTIVE"),
5719        }
5720    }
5721}
5722
5723/// Command that a policy can apply to (FOR clause).
5724/// ```sql
5725/// FOR [ALL | SELECT | INSERT | UPDATE | DELETE]
5726/// ```
5727/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createpolicy.html)
5728#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
5729#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5730#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5731pub enum CreatePolicyCommand {
5732    /// Applies to all commands.
5733    All,
5734    /// Applies to SELECT.
5735    Select,
5736    /// Applies to INSERT.
5737    Insert,
5738    /// Applies to UPDATE.
5739    Update,
5740    /// Applies to DELETE.
5741    Delete,
5742}
5743
5744impl fmt::Display for CreatePolicyCommand {
5745    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5746        match self {
5747            CreatePolicyCommand::All => write!(f, "ALL"),
5748            CreatePolicyCommand::Select => write!(f, "SELECT"),
5749            CreatePolicyCommand::Insert => write!(f, "INSERT"),
5750            CreatePolicyCommand::Update => write!(f, "UPDATE"),
5751            CreatePolicyCommand::Delete => write!(f, "DELETE"),
5752        }
5753    }
5754}
5755
5756/// DROP POLICY statement.
5757///
5758/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-droppolicy.html)
5759#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5760#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5761#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5762pub struct DropPolicy {
5763    /// `true` when `IF EXISTS` was present.
5764    pub if_exists: bool,
5765    /// Name of the policy to drop.
5766    pub name: Ident,
5767    /// Name of the table the policy applies to.
5768    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
5769    pub table_name: ObjectName,
5770    /// Optional drop behavior (`CASCADE` or `RESTRICT`).
5771    pub drop_behavior: Option<DropBehavior>,
5772}
5773
5774impl fmt::Display for DropPolicy {
5775    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5776        write!(
5777            f,
5778            "DROP POLICY {if_exists}{name} ON {table_name}",
5779            if_exists = if self.if_exists { "IF EXISTS " } else { "" },
5780            name = self.name,
5781            table_name = self.table_name
5782        )?;
5783        if let Some(ref behavior) = self.drop_behavior {
5784            write!(f, " {behavior}")?;
5785        }
5786        Ok(())
5787    }
5788}
5789
5790impl From<CreatePolicy> for crate::ast::Statement {
5791    fn from(v: CreatePolicy) -> Self {
5792        crate::ast::Statement::CreatePolicy(v)
5793    }
5794}
5795
5796impl From<DropPolicy> for crate::ast::Statement {
5797    fn from(v: DropPolicy) -> Self {
5798        crate::ast::Statement::DropPolicy(v)
5799    }
5800}
5801
5802/// ALTER POLICY statement.
5803///
5804/// ```sql
5805/// ALTER POLICY <NAME> ON <TABLE NAME> [<OPERATION>]
5806/// ```
5807/// (Postgresql-specific)
5808#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5809#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5810#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5811pub struct AlterPolicy {
5812    /// Policy name to alter.
5813    pub name: Ident,
5814    /// Target table name the policy is defined on.
5815    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
5816    pub table_name: ObjectName,
5817    /// Optional operation specific to the policy alteration.
5818    pub operation: AlterPolicyOperation,
5819}
5820
5821impl fmt::Display for AlterPolicy {
5822    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5823        write!(
5824            f,
5825            "ALTER POLICY {name} ON {table_name}{operation}",
5826            name = self.name,
5827            table_name = self.table_name,
5828            operation = self.operation
5829        )
5830    }
5831}
5832
5833impl From<AlterPolicy> for crate::ast::Statement {
5834    fn from(v: AlterPolicy) -> Self {
5835        crate::ast::Statement::AlterPolicy(v)
5836    }
5837}
5838
5839/// The handler/validator clause of a `CREATE FOREIGN DATA WRAPPER` statement.
5840///
5841/// Specifies either a named function or the absence of a function.
5842#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5843#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5844#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5845pub enum FdwRoutineClause {
5846    /// A named function, e.g. `HANDLER myhandler` or `VALIDATOR myvalidator`.
5847    Function(ObjectName),
5848    /// The `NO HANDLER` or `NO VALIDATOR` form.
5849    NoFunction,
5850}
5851
5852/// A `CREATE FOREIGN DATA WRAPPER` statement.
5853///
5854/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createforeigndatawrapper.html)
5855#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5856#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5857#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5858pub struct CreateForeignDataWrapper {
5859    /// The name of the foreign-data wrapper.
5860    pub name: Ident,
5861    /// Optional `HANDLER handler_function` or `NO HANDLER` clause.
5862    pub handler: Option<FdwRoutineClause>,
5863    /// Optional `VALIDATOR validator_function` or `NO VALIDATOR` clause.
5864    pub validator: Option<FdwRoutineClause>,
5865    /// Optional `OPTIONS (key 'value', ...)` clause.
5866    pub options: Option<Vec<CreateServerOption>>,
5867}
5868
5869impl fmt::Display for CreateForeignDataWrapper {
5870    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5871        write!(f, "CREATE FOREIGN DATA WRAPPER {}", self.name)?;
5872        if let Some(handler) = &self.handler {
5873            match handler {
5874                FdwRoutineClause::Function(name) => write!(f, " HANDLER {name}")?,
5875                FdwRoutineClause::NoFunction => write!(f, " NO HANDLER")?,
5876            }
5877        }
5878        if let Some(validator) = &self.validator {
5879            match validator {
5880                FdwRoutineClause::Function(name) => write!(f, " VALIDATOR {name}")?,
5881                FdwRoutineClause::NoFunction => write!(f, " NO VALIDATOR")?,
5882            }
5883        }
5884        if let Some(options) = &self.options {
5885            write!(f, " OPTIONS ({})", display_comma_separated(options))?;
5886        }
5887        Ok(())
5888    }
5889}
5890
5891impl From<CreateForeignDataWrapper> for crate::ast::Statement {
5892    fn from(v: CreateForeignDataWrapper) -> Self {
5893        crate::ast::Statement::CreateForeignDataWrapper(v)
5894    }
5895}
5896
5897/// A `CREATE FOREIGN TABLE` statement.
5898///
5899/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createforeigntable.html)
5900#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5901#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5902#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5903pub struct CreateForeignTable {
5904    /// The foreign table name.
5905    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
5906    pub name: ObjectName,
5907    /// Whether `IF NOT EXISTS` was specified.
5908    pub if_not_exists: bool,
5909    /// Column definitions.
5910    pub columns: Vec<ColumnDef>,
5911    /// The `SERVER server_name` clause.
5912    pub server_name: Ident,
5913    /// Optional `OPTIONS (key 'value', ...)` clause at the table level.
5914    pub options: Option<Vec<CreateServerOption>>,
5915}
5916
5917impl fmt::Display for CreateForeignTable {
5918    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5919        write!(
5920            f,
5921            "CREATE FOREIGN TABLE {if_not_exists}{name} ({columns}) SERVER {server_name}",
5922            if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
5923            name = self.name,
5924            columns = display_comma_separated(&self.columns),
5925            server_name = self.server_name,
5926        )?;
5927        if let Some(options) = &self.options {
5928            write!(f, " OPTIONS ({})", display_comma_separated(options))?;
5929        }
5930        Ok(())
5931    }
5932}
5933
5934impl From<CreateForeignTable> for crate::ast::Statement {
5935    fn from(v: CreateForeignTable) -> Self {
5936        crate::ast::Statement::CreateForeignTable(v)
5937    }
5938}
5939
5940/// CREATE AGGREGATE statement.
5941/// See <https://www.postgresql.org/docs/current/sql-createaggregate.html>
5942#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5943#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5944#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5945pub struct CreateAggregate {
5946    /// True if `OR REPLACE` was specified.
5947    pub or_replace: bool,
5948    /// The aggregate name (can be schema-qualified).
5949    pub name: ObjectName,
5950    /// Input argument types. Empty for zero-argument aggregates.
5951    pub args: Vec<DataType>,
5952    /// The options listed inside the required parentheses after the argument
5953    /// list (e.g. `SFUNC`, `STYPE`, `FINALFUNC`, `PARALLEL`, …).
5954    pub options: Vec<CreateAggregateOption>,
5955}
5956
5957impl fmt::Display for CreateAggregate {
5958    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5959        write!(f, "CREATE")?;
5960        if self.or_replace {
5961            write!(f, " OR REPLACE")?;
5962        }
5963        write!(f, " AGGREGATE {}", self.name)?;
5964        write!(f, " ({})", display_comma_separated(&self.args))?;
5965        write!(f, " (")?;
5966        for (i, option) in self.options.iter().enumerate() {
5967            if i > 0 {
5968                write!(f, ", ")?;
5969            }
5970            write!(f, "{option}")?;
5971        }
5972        write!(f, ")")
5973    }
5974}
5975
5976impl From<CreateAggregate> for crate::ast::Statement {
5977    fn from(v: CreateAggregate) -> Self {
5978        crate::ast::Statement::CreateAggregate(v)
5979    }
5980}
5981
5982/// A single option in a `CREATE AGGREGATE` options list.
5983///
5984/// See <https://www.postgresql.org/docs/current/sql-createaggregate.html>
5985#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5986#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5987#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5988pub enum CreateAggregateOption {
5989    /// `SFUNC = state_transition_function`
5990    Sfunc(ObjectName),
5991    /// `STYPE = state_data_type`
5992    Stype(DataType),
5993    /// `SSPACE = state_data_size` (in bytes)
5994    Sspace(u64),
5995    /// `FINALFUNC = final_function`
5996    Finalfunc(ObjectName),
5997    /// `FINALFUNC_EXTRA` — pass extra dummy arguments to the final function.
5998    FinalfuncExtra,
5999    /// `FINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE }`
6000    FinalfuncModify(AggregateModifyKind),
6001    /// `COMBINEFUNC = combine_function`
6002    Combinefunc(ObjectName),
6003    /// `SERIALFUNC = serial_function`
6004    Serialfunc(ObjectName),
6005    /// `DESERIALFUNC = deserial_function`
6006    Deserialfunc(ObjectName),
6007    /// `INITCOND = initial_condition` (a string literal)
6008    Initcond(Value),
6009    /// `MSFUNC = moving_state_transition_function`
6010    Msfunc(ObjectName),
6011    /// `MINVFUNC = moving_inverse_transition_function`
6012    Minvfunc(ObjectName),
6013    /// `MSTYPE = moving_state_data_type`
6014    Mstype(DataType),
6015    /// `MSSPACE = moving_state_data_size` (in bytes)
6016    Msspace(u64),
6017    /// `MFINALFUNC = moving_final_function`
6018    Mfinalfunc(ObjectName),
6019    /// `MFINALFUNC_EXTRA`
6020    MfinalfuncExtra,
6021    /// `MFINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE }`
6022    MfinalfuncModify(AggregateModifyKind),
6023    /// `MINITCOND = moving_initial_condition` (a string literal)
6024    Minitcond(Value),
6025    /// `SORTOP = sort_operator`
6026    Sortop(ObjectName),
6027    /// `PARALLEL = { SAFE | RESTRICTED | UNSAFE }`
6028    Parallel(FunctionParallel),
6029    /// `HYPOTHETICAL` — marks the aggregate as hypothetical-set.
6030    Hypothetical,
6031}
6032
6033impl fmt::Display for CreateAggregateOption {
6034    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6035        match self {
6036            Self::Sfunc(name) => write!(f, "SFUNC = {name}"),
6037            Self::Stype(data_type) => write!(f, "STYPE = {data_type}"),
6038            Self::Sspace(size) => write!(f, "SSPACE = {size}"),
6039            Self::Finalfunc(name) => write!(f, "FINALFUNC = {name}"),
6040            Self::FinalfuncExtra => write!(f, "FINALFUNC_EXTRA"),
6041            Self::FinalfuncModify(kind) => write!(f, "FINALFUNC_MODIFY = {kind}"),
6042            Self::Combinefunc(name) => write!(f, "COMBINEFUNC = {name}"),
6043            Self::Serialfunc(name) => write!(f, "SERIALFUNC = {name}"),
6044            Self::Deserialfunc(name) => write!(f, "DESERIALFUNC = {name}"),
6045            Self::Initcond(cond) => write!(f, "INITCOND = {cond}"),
6046            Self::Msfunc(name) => write!(f, "MSFUNC = {name}"),
6047            Self::Minvfunc(name) => write!(f, "MINVFUNC = {name}"),
6048            Self::Mstype(data_type) => write!(f, "MSTYPE = {data_type}"),
6049            Self::Msspace(size) => write!(f, "MSSPACE = {size}"),
6050            Self::Mfinalfunc(name) => write!(f, "MFINALFUNC = {name}"),
6051            Self::MfinalfuncExtra => write!(f, "MFINALFUNC_EXTRA"),
6052            Self::MfinalfuncModify(kind) => write!(f, "MFINALFUNC_MODIFY = {kind}"),
6053            Self::Minitcond(cond) => write!(f, "MINITCOND = {cond}"),
6054            Self::Sortop(name) => write!(f, "SORTOP = {name}"),
6055            Self::Parallel(parallel) => {
6056                let kind = match parallel {
6057                    FunctionParallel::Safe => "SAFE",
6058                    FunctionParallel::Restricted => "RESTRICTED",
6059                    FunctionParallel::Unsafe => "UNSAFE",
6060                };
6061                write!(f, "PARALLEL = {kind}")
6062            }
6063            Self::Hypothetical => write!(f, "HYPOTHETICAL"),
6064        }
6065    }
6066}
6067
6068/// Modifier kind for `FINALFUNC_MODIFY` / `MFINALFUNC_MODIFY` in `CREATE AGGREGATE`.
6069///
6070/// See <https://www.postgresql.org/docs/current/sql-createaggregate.html>
6071#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6072#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6073#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6074pub enum AggregateModifyKind {
6075    /// The final function does not modify the transition state.
6076    ReadOnly,
6077    /// The transition state may be shared between aggregate calls.
6078    Shareable,
6079    /// The final function may modify the transition state.
6080    ReadWrite,
6081}
6082
6083impl fmt::Display for AggregateModifyKind {
6084    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6085        match self {
6086            Self::ReadOnly => write!(f, "READ_ONLY"),
6087            Self::Shareable => write!(f, "SHAREABLE"),
6088            Self::ReadWrite => write!(f, "READ_WRITE"),
6089        }
6090    }
6091}
6092
6093/// `CREATE TEXT SEARCH CONFIGURATION` statement.
6094///
6095/// Note: this is a PostgreSQL-specific statement.
6096/// <https://www.postgresql.org/docs/current/sql-createtsconfig.html>
6097#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6098#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6099#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6100pub struct CreateTextSearchConfiguration {
6101    /// Name of the text search configuration being created.
6102    pub name: ObjectName,
6103    /// Options list — must include `PARSER = parser_name`.
6104    pub options: Vec<SqlOption>,
6105}
6106
6107impl fmt::Display for CreateTextSearchConfiguration {
6108    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6109        write!(
6110            f,
6111            "CREATE TEXT SEARCH CONFIGURATION {name} ({options})",
6112            name = self.name,
6113            options = display_comma_separated(&self.options),
6114        )
6115    }
6116}
6117
6118impl From<CreateTextSearchConfiguration> for crate::ast::Statement {
6119    fn from(v: CreateTextSearchConfiguration) -> Self {
6120        crate::ast::Statement::CreateTextSearchConfiguration(v)
6121    }
6122}
6123
6124/// `CREATE TEXT SEARCH DICTIONARY` statement.
6125///
6126/// Note: this is a PostgreSQL-specific statement.
6127/// <https://www.postgresql.org/docs/current/sql-createtsdictionary.html>
6128#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6129#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6130#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6131pub struct CreateTextSearchDictionary {
6132    /// Name of the text search dictionary being created.
6133    pub name: ObjectName,
6134    /// Options list — must include `TEMPLATE = template_name`.
6135    pub options: Vec<SqlOption>,
6136}
6137
6138impl fmt::Display for CreateTextSearchDictionary {
6139    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6140        write!(
6141            f,
6142            "CREATE TEXT SEARCH DICTIONARY {name} ({options})",
6143            name = self.name,
6144            options = display_comma_separated(&self.options),
6145        )
6146    }
6147}
6148
6149impl From<CreateTextSearchDictionary> for crate::ast::Statement {
6150    fn from(v: CreateTextSearchDictionary) -> Self {
6151        crate::ast::Statement::CreateTextSearchDictionary(v)
6152    }
6153}
6154
6155/// `CREATE TEXT SEARCH PARSER` statement.
6156///
6157/// Note: this is a PostgreSQL-specific statement.
6158/// <https://www.postgresql.org/docs/current/sql-createtsparser.html>
6159#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6160#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6161#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6162pub struct CreateTextSearchParser {
6163    /// Name of the text search parser being created.
6164    pub name: ObjectName,
6165    /// Options list — must include `START`, `GETTOKEN`, `END`, `LEXTYPES` (and optionally `HEADLINE`).
6166    pub options: Vec<SqlOption>,
6167}
6168
6169impl fmt::Display for CreateTextSearchParser {
6170    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6171        write!(
6172            f,
6173            "CREATE TEXT SEARCH PARSER {name} ({options})",
6174            name = self.name,
6175            options = display_comma_separated(&self.options),
6176        )
6177    }
6178}
6179
6180impl From<CreateTextSearchParser> for crate::ast::Statement {
6181    fn from(v: CreateTextSearchParser) -> Self {
6182        crate::ast::Statement::CreateTextSearchParser(v)
6183    }
6184}
6185
6186/// `CREATE TEXT SEARCH TEMPLATE` statement.
6187///
6188/// Note: this is a PostgreSQL-specific statement.
6189/// <https://www.postgresql.org/docs/current/sql-createtstemplate.html>
6190#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6191#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6192#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6193pub struct CreateTextSearchTemplate {
6194    /// Name of the text search template being created.
6195    pub name: ObjectName,
6196    /// Options list — must include `LEXIZE` (and optionally `INIT`).
6197    pub options: Vec<SqlOption>,
6198}
6199
6200impl fmt::Display for CreateTextSearchTemplate {
6201    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6202        write!(
6203            f,
6204            "CREATE TEXT SEARCH TEMPLATE {name} ({options})",
6205            name = self.name,
6206            options = display_comma_separated(&self.options),
6207        )
6208    }
6209}
6210
6211impl From<CreateTextSearchTemplate> for crate::ast::Statement {
6212    fn from(v: CreateTextSearchTemplate) -> Self {
6213        crate::ast::Statement::CreateTextSearchTemplate(v)
6214    }
6215}
6216
6217/// `ALTER DOMAIN` statement.
6218///
6219/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterdomain.html)
6220#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6221#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6222#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6223pub struct AlterDomain {
6224    /// Name of the domain being altered.
6225    pub name: ObjectName,
6226    /// The operation to perform.
6227    pub operation: AlterDomainOperation,
6228}
6229
6230/// An [AlterDomain] operation.
6231#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6232#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6233#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6234pub enum AlterDomainOperation {
6235    /// `ADD CONSTRAINT constraint_name CHECK (expr) [NOT VALID]`
6236    AddConstraint {
6237        /// The constraint to add.
6238        constraint: TableConstraint,
6239        /// Whether `NOT VALID` was specified.
6240        not_valid: bool,
6241    },
6242    /// `DROP CONSTRAINT [IF EXISTS] constraint_name [CASCADE | RESTRICT]`
6243    DropConstraint {
6244        /// Whether `IF EXISTS` was specified.
6245        if_exists: bool,
6246        /// Name of the constraint to drop.
6247        name: Ident,
6248        /// Optional drop behavior.
6249        drop_behavior: Option<DropBehavior>,
6250    },
6251    /// `RENAME CONSTRAINT old_name TO new_name`
6252    RenameConstraint {
6253        /// Existing constraint name.
6254        old_name: Ident,
6255        /// New constraint name.
6256        new_name: Ident,
6257    },
6258    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
6259    OwnerTo(Owner),
6260    /// `RENAME TO new_name`
6261    RenameTo {
6262        /// New name for the domain.
6263        new_name: Ident,
6264    },
6265    /// `SET SCHEMA schema_name`
6266    SetSchema {
6267        /// The target schema name.
6268        schema_name: ObjectName,
6269    },
6270    /// `SET DEFAULT expr`
6271    SetDefault {
6272        /// Default value expression.
6273        default: Expr,
6274    },
6275    /// `DROP DEFAULT`
6276    DropDefault,
6277    /// `VALIDATE CONSTRAINT constraint_name`
6278    ValidateConstraint {
6279        /// Name of the constraint to validate.
6280        name: Ident,
6281    },
6282}
6283
6284impl fmt::Display for AlterDomain {
6285    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6286        write!(f, "ALTER DOMAIN {} {}", self.name, self.operation)
6287    }
6288}
6289
6290impl fmt::Display for AlterDomainOperation {
6291    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6292        match self {
6293            AlterDomainOperation::AddConstraint {
6294                constraint,
6295                not_valid,
6296            } => {
6297                write!(f, "ADD {constraint}")?;
6298                if *not_valid {
6299                    write!(f, " NOT VALID")?;
6300                }
6301                Ok(())
6302            }
6303            AlterDomainOperation::DropConstraint {
6304                if_exists,
6305                name,
6306                drop_behavior,
6307            } => {
6308                write!(f, "DROP CONSTRAINT")?;
6309                if *if_exists {
6310                    write!(f, " IF EXISTS")?;
6311                }
6312                write!(f, " {name}")?;
6313                if let Some(behavior) = drop_behavior {
6314                    write!(f, " {behavior}")?;
6315                }
6316                Ok(())
6317            }
6318            AlterDomainOperation::RenameConstraint { old_name, new_name } => {
6319                write!(f, "RENAME CONSTRAINT {old_name} TO {new_name}")
6320            }
6321            AlterDomainOperation::OwnerTo(owner) => write!(f, "OWNER TO {owner}"),
6322            AlterDomainOperation::RenameTo { new_name } => write!(f, "RENAME TO {new_name}"),
6323            AlterDomainOperation::SetSchema { schema_name } => {
6324                write!(f, "SET SCHEMA {schema_name}")
6325            }
6326            AlterDomainOperation::SetDefault { default } => write!(f, "SET DEFAULT {default}"),
6327            AlterDomainOperation::DropDefault => write!(f, "DROP DEFAULT"),
6328            AlterDomainOperation::ValidateConstraint { name } => {
6329                write!(f, "VALIDATE CONSTRAINT {name}")
6330            }
6331        }
6332    }
6333}
6334
6335/// The target of a `CREATE PUBLICATION` statement: which rows to publish.
6336///
6337/// See <https://www.postgresql.org/docs/current/sql-createpublication.html>
6338#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6339#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6340#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6341pub enum PublicationTarget {
6342    /// `FOR ALL TABLES`
6343    AllTables,
6344    /// `FOR TABLE table [, ...]`
6345    Tables(Vec<ObjectName>),
6346    /// `FOR TABLES IN SCHEMA schema [, ...]`
6347    TablesInSchema(Vec<Ident>),
6348}
6349
6350impl fmt::Display for PublicationTarget {
6351    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6352        match self {
6353            PublicationTarget::AllTables => write!(f, "FOR ALL TABLES"),
6354            PublicationTarget::Tables(tables) => {
6355                write!(f, "FOR TABLE {}", display_comma_separated(tables))
6356            }
6357            PublicationTarget::TablesInSchema(schemas) => {
6358                write!(
6359                    f,
6360                    "FOR TABLES IN SCHEMA {}",
6361                    display_comma_separated(schemas)
6362                )
6363            }
6364        }
6365    }
6366}
6367
6368impl From<AlterDomain> for crate::ast::Statement {
6369    fn from(a: AlterDomain) -> Self {
6370        crate::ast::Statement::AlterDomain(a)
6371    }
6372}
6373
6374/// `ALTER TRIGGER name ON table_name RENAME TO new_name` statement.
6375///
6376/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-altertrigger.html)
6377#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6378#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6379#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6380pub struct AlterTrigger {
6381    /// Name of the trigger being altered.
6382    pub name: Ident,
6383    /// Name of the table the trigger is defined on.
6384    pub table_name: ObjectName,
6385    /// The operation to perform.
6386    pub operation: AlterTriggerOperation,
6387}
6388
6389/// An [AlterTrigger] operation.
6390#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6391#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6392#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6393pub enum AlterTriggerOperation {
6394    /// `RENAME TO new_name`
6395    RenameTo {
6396        /// New name for the trigger.
6397        new_name: Ident,
6398    },
6399}
6400
6401impl fmt::Display for AlterTrigger {
6402    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6403        write!(
6404            f,
6405            "ALTER TRIGGER {} ON {} {}",
6406            self.name, self.table_name, self.operation
6407        )
6408    }
6409}
6410
6411impl fmt::Display for AlterTriggerOperation {
6412    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6413        match self {
6414            AlterTriggerOperation::RenameTo { new_name } => write!(f, "RENAME TO {new_name}"),
6415        }
6416    }
6417}
6418
6419impl From<AlterTrigger> for crate::ast::Statement {
6420    fn from(a: AlterTrigger) -> Self {
6421        crate::ast::Statement::AlterTrigger(a)
6422    }
6423}
6424
6425/// `ALTER EXTENSION` statement.
6426///
6427/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterextension.html)
6428#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6429#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6430#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6431pub struct AlterExtension {
6432    /// Name of the extension being altered.
6433    pub name: Ident,
6434    /// The operation to perform.
6435    pub operation: AlterExtensionOperation,
6436}
6437
6438/// An [AlterExtension] operation.
6439#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6440#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6441#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6442pub enum AlterExtensionOperation {
6443    /// `UPDATE [ TO new_version ]`
6444    UpdateTo {
6445        /// Optional target version string or identifier.
6446        version: Option<Ident>,
6447    },
6448    /// `SET SCHEMA schema_name`
6449    SetSchema {
6450        /// The target schema name.
6451        schema_name: ObjectName,
6452    },
6453    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
6454    OwnerTo(Owner),
6455    /// `RENAME TO new_name`
6456    RenameTo {
6457        /// New name for the extension.
6458        new_name: Ident,
6459    },
6460}
6461
6462impl fmt::Display for AlterExtension {
6463    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6464        write!(f, "ALTER EXTENSION {} {}", self.name, self.operation)
6465    }
6466}
6467
6468impl fmt::Display for AlterExtensionOperation {
6469    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6470        match self {
6471            AlterExtensionOperation::UpdateTo { version } => {
6472                write!(f, "UPDATE")?;
6473                if let Some(v) = version {
6474                    write!(f, " TO {v}")?;
6475                }
6476                Ok(())
6477            }
6478            AlterExtensionOperation::SetSchema { schema_name } => {
6479                write!(f, "SET SCHEMA {schema_name}")
6480            }
6481            AlterExtensionOperation::OwnerTo(owner) => write!(f, "OWNER TO {owner}"),
6482            AlterExtensionOperation::RenameTo { new_name } => write!(f, "RENAME TO {new_name}"),
6483        }
6484    }
6485}
6486
6487impl From<AlterExtension> for crate::ast::Statement {
6488    fn from(a: AlterExtension) -> Self {
6489        crate::ast::Statement::AlterExtension(a)
6490    }
6491}
6492
6493/// A `CREATE PUBLICATION` statement.
6494///
6495/// Note: this is a PostgreSQL-specific statement.
6496/// <https://www.postgresql.org/docs/current/sql-createpublication.html>
6497#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6498#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6499#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6500pub struct CreatePublication {
6501    /// The publication name.
6502    pub name: Ident,
6503    /// Optional target specification (`FOR ALL TABLES`, `FOR TABLE ...`, or `FOR TABLES IN SCHEMA ...`).
6504    pub target: Option<PublicationTarget>,
6505    /// Optional `WITH (key = value, ...)` clause.
6506    pub with_options: Vec<SqlOption>,
6507}
6508
6509impl fmt::Display for CreatePublication {
6510    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6511        write!(f, "CREATE PUBLICATION {}", self.name)?;
6512        if let Some(target) = &self.target {
6513            write!(f, " {target}")?;
6514        }
6515        if !self.with_options.is_empty() {
6516            write!(f, " WITH ({})", display_comma_separated(&self.with_options))?;
6517        }
6518        Ok(())
6519    }
6520}
6521
6522impl From<CreatePublication> for crate::ast::Statement {
6523    fn from(v: CreatePublication) -> Self {
6524        crate::ast::Statement::CreatePublication(v)
6525    }
6526}
6527
6528/// A `CREATE SUBSCRIPTION` statement.
6529///
6530/// Note: this is a PostgreSQL-specific statement.
6531/// <https://www.postgresql.org/docs/current/sql-createsubscription.html>
6532#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6533#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6534#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6535pub struct CreateSubscription {
6536    /// The subscription name.
6537    pub name: Ident,
6538    /// The `CONNECTION 'conninfo'` string.
6539    pub connection: Value,
6540    /// The `PUBLICATION publication_name [, ...]` list.
6541    pub publications: Vec<Ident>,
6542    /// Optional `WITH (key = value, ...)` clause.
6543    pub with_options: Vec<SqlOption>,
6544}
6545
6546impl fmt::Display for CreateSubscription {
6547    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6548        write!(
6549            f,
6550            "CREATE SUBSCRIPTION {name} CONNECTION {connection} PUBLICATION {publications}",
6551            name = self.name,
6552            connection = self.connection,
6553            publications = display_comma_separated(&self.publications),
6554        )?;
6555        if !self.with_options.is_empty() {
6556            write!(f, " WITH ({})", display_comma_separated(&self.with_options))?;
6557        }
6558        Ok(())
6559    }
6560}
6561
6562impl From<CreateSubscription> for crate::ast::Statement {
6563    fn from(v: CreateSubscription) -> Self {
6564        crate::ast::Statement::CreateSubscription(v)
6565    }
6566}
6567
6568/// The function binding kind for a `CREATE CAST` statement.
6569///
6570/// Note: this is a PostgreSQL-specific construct.
6571#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6572#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6573#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6574pub enum CastFunctionKind {
6575    /// `WITH FUNCTION function_name(arg_types)`
6576    WithFunction {
6577        /// The name of the cast implementation function.
6578        function_name: ObjectName,
6579        /// Optional argument type list. Empty if the function has no arguments
6580        /// declared in the `CREATE CAST` clause.
6581        argument_types: Vec<DataType>,
6582    },
6583    /// `WITHOUT FUNCTION`
6584    WithoutFunction,
6585    /// `WITH INOUT`
6586    WithInout,
6587}
6588
6589impl fmt::Display for CastFunctionKind {
6590    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6591        match self {
6592            CastFunctionKind::WithFunction {
6593                function_name,
6594                argument_types,
6595            } => {
6596                write!(f, "WITH FUNCTION {function_name}")?;
6597                if !argument_types.is_empty() {
6598                    write!(f, "({})", display_comma_separated(argument_types))?;
6599                }
6600                Ok(())
6601            }
6602            CastFunctionKind::WithoutFunction => write!(f, "WITHOUT FUNCTION"),
6603            CastFunctionKind::WithInout => write!(f, "WITH INOUT"),
6604        }
6605    }
6606}
6607
6608/// A kind of extended statistics collected by `CREATE STATISTICS`.
6609///
6610/// Note: this is a PostgreSQL-specific concept.
6611/// <https://www.postgresql.org/docs/current/sql-createstatistics.html>
6612#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6613#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6614#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6615pub enum StatisticsKind {
6616    /// `ndistinct` — n-distinct statistics
6617    NDistinct,
6618    /// `dependencies` — functional dependency statistics
6619    Dependencies,
6620    /// `mcv` — most-common-values statistics
6621    Mcv,
6622}
6623
6624impl fmt::Display for StatisticsKind {
6625    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6626        match self {
6627            StatisticsKind::NDistinct => write!(f, "ndistinct"),
6628            StatisticsKind::Dependencies => write!(f, "dependencies"),
6629            StatisticsKind::Mcv => write!(f, "mcv"),
6630        }
6631    }
6632}
6633
6634/// The object kind targeted by a `SECURITY LABEL` statement.
6635///
6636/// See <https://www.postgresql.org/docs/current/sql-securitylabel.html>
6637#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6638#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6639#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6640pub enum SecurityLabelObjectKind {
6641    /// `TABLE name`
6642    Table,
6643    /// `COLUMN name.colname`
6644    Column,
6645    /// `DATABASE name`
6646    Database,
6647    /// `DOMAIN name`
6648    Domain,
6649    /// `FUNCTION name`
6650    Function,
6651    /// `ROLE name`
6652    Role,
6653    /// `SCHEMA name`
6654    Schema,
6655    /// `SEQUENCE name`
6656    Sequence,
6657    /// `TYPE name`
6658    Type,
6659    /// `VIEW name`
6660    View,
6661    /// `MATERIALIZED VIEW name`
6662    MaterializedView,
6663}
6664
6665impl fmt::Display for SecurityLabelObjectKind {
6666    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6667        match self {
6668            SecurityLabelObjectKind::Table => write!(f, "TABLE"),
6669            SecurityLabelObjectKind::Column => write!(f, "COLUMN"),
6670            SecurityLabelObjectKind::Database => write!(f, "DATABASE"),
6671            SecurityLabelObjectKind::Domain => write!(f, "DOMAIN"),
6672            SecurityLabelObjectKind::Function => write!(f, "FUNCTION"),
6673            SecurityLabelObjectKind::Role => write!(f, "ROLE"),
6674            SecurityLabelObjectKind::Schema => write!(f, "SCHEMA"),
6675            SecurityLabelObjectKind::Sequence => write!(f, "SEQUENCE"),
6676            SecurityLabelObjectKind::Type => write!(f, "TYPE"),
6677            SecurityLabelObjectKind::View => write!(f, "VIEW"),
6678            SecurityLabelObjectKind::MaterializedView => write!(f, "MATERIALIZED VIEW"),
6679        }
6680    }
6681}
6682
6683/// The context in which a cast may be invoked automatically.
6684///
6685/// Note: this is a PostgreSQL-specific construct.
6686#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6687#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6688#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6689pub enum CastContext {
6690    /// No `AS` clause — explicit cast only (default).
6691    Explicit,
6692    /// `AS ASSIGNMENT`
6693    Assignment,
6694    /// `AS IMPLICIT`
6695    Implicit,
6696}
6697
6698impl fmt::Display for CastContext {
6699    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6700        match self {
6701            CastContext::Explicit => Ok(()),
6702            CastContext::Assignment => write!(f, " AS ASSIGNMENT"),
6703            CastContext::Implicit => write!(f, " AS IMPLICIT"),
6704        }
6705    }
6706}
6707
6708/// A `CREATE CAST` statement.
6709///
6710/// Note: this is a PostgreSQL-specific statement.
6711/// <https://www.postgresql.org/docs/current/sql-createcast.html>
6712#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6713#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6714#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6715pub struct CreateCast {
6716    /// The source type.
6717    pub source_type: DataType,
6718    /// The target type.
6719    pub target_type: DataType,
6720    /// How the cast is implemented.
6721    pub function_kind: CastFunctionKind,
6722    /// The cast context (explicit, assignment, or implicit).
6723    pub cast_context: CastContext,
6724}
6725
6726impl fmt::Display for CreateCast {
6727    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6728        write!(
6729            f,
6730            "CREATE CAST ({source} AS {target}) {function_kind}{context}",
6731            source = self.source_type,
6732            target = self.target_type,
6733            function_kind = self.function_kind,
6734            context = self.cast_context,
6735        )
6736    }
6737}
6738
6739impl From<CreateCast> for crate::ast::Statement {
6740    fn from(v: CreateCast) -> Self {
6741        crate::ast::Statement::CreateCast(v)
6742    }
6743}
6744
6745/// A `CREATE CONVERSION` statement.
6746///
6747/// Note: this is a PostgreSQL-specific statement.
6748/// <https://www.postgresql.org/docs/current/sql-createconversion.html>
6749#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6750#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6751#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6752pub struct CreateConversion {
6753    /// The conversion name.
6754    pub name: ObjectName,
6755    /// Whether this is a `DEFAULT` conversion.
6756    pub is_default: bool,
6757    /// The source encoding name (a string literal like `'LATIN1'`).
6758    pub source_encoding: String,
6759    /// The destination encoding name (a string literal like `'UTF8'`).
6760    pub destination_encoding: String,
6761    /// The conversion function name.
6762    pub function_name: ObjectName,
6763}
6764
6765impl fmt::Display for CreateConversion {
6766    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6767        write!(f, "CREATE")?;
6768        if self.is_default {
6769            write!(f, " DEFAULT")?;
6770        }
6771        write!(
6772            f,
6773            " CONVERSION {name} FOR '{source}' TO '{destination}' FROM {function}",
6774            name = self.name,
6775            source = self.source_encoding,
6776            destination = self.destination_encoding,
6777            function = self.function_name,
6778        )
6779    }
6780}
6781
6782impl From<CreateConversion> for crate::ast::Statement {
6783    fn from(v: CreateConversion) -> Self {
6784        crate::ast::Statement::CreateConversion(v)
6785    }
6786}
6787
6788/// A `CREATE LANGUAGE` statement.
6789///
6790/// Note: this is a PostgreSQL-specific statement.
6791/// <https://www.postgresql.org/docs/current/sql-createlanguage.html>
6792#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6793#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6794#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6795pub struct CreateLanguage {
6796    /// The language name.
6797    pub name: Ident,
6798    /// Whether `OR REPLACE` was specified.
6799    pub or_replace: bool,
6800    /// Whether `TRUSTED` was specified.
6801    pub trusted: bool,
6802    /// Whether `PROCEDURAL` was specified.
6803    pub procedural: bool,
6804    /// Optional `HANDLER handler_function` clause.
6805    pub handler: Option<ObjectName>,
6806    /// Optional `INLINE inline_function` clause.
6807    pub inline_handler: Option<ObjectName>,
6808    /// Optional `VALIDATOR validator_function` clause.
6809    pub validator: Option<ObjectName>,
6810}
6811
6812impl fmt::Display for CreateLanguage {
6813    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6814        write!(f, "CREATE")?;
6815        if self.or_replace {
6816            write!(f, " OR REPLACE")?;
6817        }
6818        if self.trusted {
6819            write!(f, " TRUSTED")?;
6820        }
6821        if self.procedural {
6822            write!(f, " PROCEDURAL")?;
6823        }
6824        write!(f, " LANGUAGE {}", self.name)?;
6825        if let Some(handler) = &self.handler {
6826            write!(f, " HANDLER {handler}")?;
6827        }
6828        if let Some(inline) = &self.inline_handler {
6829            write!(f, " INLINE {inline}")?;
6830        }
6831        if let Some(validator) = &self.validator {
6832            write!(f, " VALIDATOR {validator}")?;
6833        }
6834        Ok(())
6835    }
6836}
6837
6838/// A `CREATE STATISTICS` statement.
6839///
6840/// Note: this is a PostgreSQL-specific statement.
6841/// <https://www.postgresql.org/docs/current/sql-createstatistics.html>
6842#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6843#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6844#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6845pub struct CreateStatistics {
6846    /// Optional `IF NOT EXISTS` clause.
6847    pub if_not_exists: bool,
6848    /// The statistics object name, e.g. `public.s`.
6849    pub name: ObjectName,
6850    /// Optional `(ndistinct, dependencies, mcv)` kind list.
6851    pub kinds: Vec<StatisticsKind>,
6852    /// The expressions (columns or arbitrary expressions) to collect statistics on.
6853    pub on: Vec<Expr>,
6854    /// The table to collect statistics from.
6855    pub from: ObjectName,
6856}
6857
6858impl fmt::Display for CreateStatistics {
6859    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6860        write!(f, "CREATE STATISTICS")?;
6861        if self.if_not_exists {
6862            write!(f, " IF NOT EXISTS")?;
6863        }
6864        write!(f, " {}", self.name)?;
6865        if !self.kinds.is_empty() {
6866            write!(f, " ({})", display_comma_separated(&self.kinds))?;
6867        }
6868        write!(f, " ON {}", display_comma_separated(&self.on))?;
6869        write!(f, " FROM {}", self.from)?;
6870        Ok(())
6871    }
6872}
6873
6874/// A `SECURITY LABEL` statement.
6875///
6876/// Note: this is a PostgreSQL-specific statement.
6877/// <https://www.postgresql.org/docs/current/sql-securitylabel.html>
6878#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6879#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6880#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6881pub struct SecurityLabel {
6882    /// Optional `FOR provider_name` clause.
6883    pub provider: Option<Ident>,
6884    /// The kind of object the label is applied to.
6885    pub object_kind: SecurityLabelObjectKind,
6886    /// The name of the object the label is applied to.
6887    pub object_name: ObjectName,
6888    /// The label string, or `None` for `IS NULL`.
6889    pub label: Option<Value>,
6890}
6891
6892impl fmt::Display for SecurityLabel {
6893    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6894        write!(f, "SECURITY LABEL")?;
6895        if let Some(provider) = &self.provider {
6896            write!(f, " FOR {provider}")?;
6897        }
6898        write!(f, " ON {} {}", self.object_kind, self.object_name)?;
6899        write!(f, " IS ")?;
6900        match &self.label {
6901            Some(label) => write!(f, "{label}"),
6902            None => write!(f, "NULL"),
6903        }
6904    }
6905}
6906
6907impl From<SecurityLabel> for crate::ast::Statement {
6908    fn from(v: SecurityLabel) -> Self {
6909        crate::ast::Statement::SecurityLabel(v)
6910    }
6911}
6912
6913/// The role specification in a `CREATE USER MAPPING` statement.
6914///
6915/// See <https://www.postgresql.org/docs/current/sql-createusermapping.html>
6916#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6917#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6918#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6919pub enum UserMappingUser {
6920    /// A specific role name.
6921    Ident(Ident),
6922    /// `USER` (current user)
6923    User,
6924    /// `CURRENT_ROLE`
6925    CurrentRole,
6926    /// `CURRENT_USER`
6927    CurrentUser,
6928    /// `PUBLIC`
6929    Public,
6930}
6931
6932impl fmt::Display for UserMappingUser {
6933    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6934        match self {
6935            UserMappingUser::Ident(ident) => write!(f, "{ident}"),
6936            UserMappingUser::User => write!(f, "USER"),
6937            UserMappingUser::CurrentRole => write!(f, "CURRENT_ROLE"),
6938            UserMappingUser::CurrentUser => write!(f, "CURRENT_USER"),
6939            UserMappingUser::Public => write!(f, "PUBLIC"),
6940        }
6941    }
6942}
6943
6944/// A `CREATE USER MAPPING` statement.
6945///
6946/// Note: this is a PostgreSQL-specific statement.
6947/// <https://www.postgresql.org/docs/current/sql-createusermapping.html>
6948#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6949#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6950#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6951pub struct CreateUserMapping {
6952    /// `IF NOT EXISTS`
6953    pub if_not_exists: bool,
6954    /// The user/role for the mapping.
6955    pub user: UserMappingUser,
6956    /// The foreign server name.
6957    pub server_name: Ident,
6958    /// Optional `OPTIONS (key 'value', ...)` clause.
6959    pub options: Option<Vec<CreateServerOption>>,
6960}
6961
6962impl fmt::Display for CreateUserMapping {
6963    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6964        write!(f, "CREATE USER MAPPING")?;
6965        if self.if_not_exists {
6966            write!(f, " IF NOT EXISTS")?;
6967        }
6968        write!(f, " FOR {} SERVER {}", self.user, self.server_name)?;
6969        if let Some(options) = &self.options {
6970            write!(
6971                f,
6972                " OPTIONS ({})",
6973                display_comma_separated(options)
6974            )?;
6975        }
6976        Ok(())
6977    }
6978}
6979
6980impl From<CreateLanguage> for crate::ast::Statement {
6981    fn from(v: CreateLanguage) -> Self {
6982        crate::ast::Statement::CreateLanguage(v)
6983    }
6984}
6985
6986/// The event that triggers a rule.
6987///
6988/// Note: this is a PostgreSQL-specific construct.
6989#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6990#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6991#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6992pub enum RuleEvent {
6993    /// `ON SELECT` rule.
6994    Select,
6995    /// `ON INSERT` rule.
6996    Insert,
6997    /// `ON UPDATE` rule.
6998    Update,
6999    /// `ON DELETE` rule.
7000    Delete,
7001}
7002
7003impl fmt::Display for RuleEvent {
7004    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7005        match self {
7006            RuleEvent::Select => write!(f, "SELECT"),
7007            RuleEvent::Insert => write!(f, "INSERT"),
7008            RuleEvent::Update => write!(f, "UPDATE"),
7009            RuleEvent::Delete => write!(f, "DELETE"),
7010        }
7011    }
7012}
7013
7014impl From<CreateStatistics> for crate::ast::Statement {
7015    fn from(v: CreateStatistics) -> Self {
7016        crate::ast::Statement::CreateStatistics(v)
7017    }
7018}
7019
7020/// The type of access method in `CREATE ACCESS METHOD`.
7021///
7022/// Note: this is a PostgreSQL-specific concept.
7023/// <https://www.postgresql.org/docs/current/sql-create-access-method.html>
7024#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
7025#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7026#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
7027pub enum AccessMethodType {
7028    /// `INDEX` — an index access method
7029    Index,
7030    /// `TABLE` — a table access method
7031    Table,
7032}
7033
7034impl fmt::Display for AccessMethodType {
7035    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7036        match self {
7037            AccessMethodType::Index => write!(f, "INDEX"),
7038            AccessMethodType::Table => write!(f, "TABLE"),
7039        }
7040    }
7041}
7042
7043/// The action performed by a rule.
7044///
7045/// Note: this is a PostgreSQL-specific construct.
7046#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
7047#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7048#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
7049pub enum RuleAction {
7050    /// `NOTHING`
7051    Nothing,
7052    /// One or more statements (parenthesized when more than one).
7053    Statements(Vec<crate::ast::Statement>),
7054}
7055
7056impl fmt::Display for RuleAction {
7057    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7058        match self {
7059            RuleAction::Nothing => write!(f, "NOTHING"),
7060            RuleAction::Statements(stmts) => {
7061                if stmts.len() == 1 {
7062                    write!(f, "{}", stmts[0])
7063                } else {
7064                    write!(f, "(")?;
7065                    for (i, stmt) in stmts.iter().enumerate() {
7066                        if i > 0 {
7067                            write!(f, "; ")?;
7068                        }
7069                        write!(f, "{stmt}")?;
7070                    }
7071                    write!(f, ")")
7072                }
7073            }
7074        }
7075    }
7076}
7077
7078/// A `CREATE RULE` statement.
7079///
7080/// Note: this is a PostgreSQL-specific statement.
7081/// <https://www.postgresql.org/docs/current/sql-createrule.html>
7082#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
7083#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7084#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
7085pub struct CreateRule {
7086    /// The rule name.
7087    pub name: Ident,
7088    /// The event that triggers the rule.
7089    pub event: RuleEvent,
7090    /// The table the rule applies to.
7091    pub table: ObjectName,
7092    /// Optional `WHERE condition` clause.
7093    pub condition: Option<Expr>,
7094    /// Whether the rule is `INSTEAD` (true) or `ALSO` (false).
7095    pub instead: bool,
7096    /// The action(s) taken by the rule.
7097    pub action: RuleAction,
7098}
7099
7100impl fmt::Display for CreateRule {
7101    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7102        write!(
7103            f,
7104            "CREATE RULE {name} AS ON {event} TO {table}",
7105            name = self.name,
7106            event = self.event,
7107            table = self.table,
7108        )?;
7109        if let Some(condition) = &self.condition {
7110            write!(f, " WHERE {condition}")?;
7111        }
7112        write!(f, " DO")?;
7113        if self.instead {
7114            write!(f, " INSTEAD")?;
7115        } else {
7116            write!(f, " ALSO")?;
7117        }
7118        write!(f, " {}", self.action)
7119    }
7120}
7121
7122impl From<CreateRule> for crate::ast::Statement {
7123    fn from(v: CreateRule) -> Self {
7124        crate::ast::Statement::CreateRule(v)
7125    }
7126}
7127
7128/// A `CREATE ACCESS METHOD` statement.
7129///
7130/// Note: this is a PostgreSQL-specific statement.
7131/// <https://www.postgresql.org/docs/current/sql-create-access-method.html>
7132#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
7133#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7134#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
7135pub struct CreateAccessMethod {
7136    /// The access method name.
7137    pub name: Ident,
7138    /// `TYPE INDEX | TABLE`
7139    pub method_type: AccessMethodType,
7140    /// `HANDLER handler_function`
7141    pub handler: ObjectName,
7142}
7143
7144impl fmt::Display for CreateAccessMethod {
7145    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7146        write!(
7147            f,
7148            "CREATE ACCESS METHOD {name} TYPE {method_type} HANDLER {handler}",
7149            name = self.name,
7150            method_type = self.method_type,
7151            handler = self.handler,
7152        )
7153    }
7154}
7155
7156impl From<CreateAccessMethod> for crate::ast::Statement {
7157    fn from(v: CreateAccessMethod) -> Self {
7158        crate::ast::Statement::CreateAccessMethod(v)
7159    }
7160}
7161
7162/// An event name for `CREATE EVENT TRIGGER`.
7163///
7164/// Note: this is a PostgreSQL-specific concept.
7165/// <https://www.postgresql.org/docs/current/sql-createeventtrigger.html>
7166#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
7167#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7168#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
7169pub enum EventTriggerEvent {
7170    /// `ddl_command_start`
7171    DdlCommandStart,
7172    /// `ddl_command_end`
7173    DdlCommandEnd,
7174    /// `table_rewrite`
7175    TableRewrite,
7176    /// `sql_drop`
7177    SqlDrop,
7178}
7179
7180impl fmt::Display for EventTriggerEvent {
7181    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7182        match self {
7183            EventTriggerEvent::DdlCommandStart => write!(f, "ddl_command_start"),
7184            EventTriggerEvent::DdlCommandEnd => write!(f, "ddl_command_end"),
7185            EventTriggerEvent::TableRewrite => write!(f, "table_rewrite"),
7186            EventTriggerEvent::SqlDrop => write!(f, "sql_drop"),
7187        }
7188    }
7189}
7190
7191/// A `CREATE EVENT TRIGGER` statement.
7192///
7193/// Note: this is a PostgreSQL-specific statement.
7194/// <https://www.postgresql.org/docs/current/sql-createeventtrigger.html>
7195#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
7196#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7197#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
7198pub struct CreateEventTrigger {
7199    /// The trigger name.
7200    pub name: Ident,
7201    /// The event that fires the trigger.
7202    pub event: EventTriggerEvent,
7203    /// Optional `WHEN TAG IN ('tag', ...)` filter.
7204    pub when_tags: Option<Vec<Value>>,
7205    /// The handler function name (from `EXECUTE FUNCTION name()`).
7206    pub execute: ObjectName,
7207    /// Whether `PROCEDURE` was used instead of `FUNCTION` (older alias).
7208    pub is_procedure: bool,
7209}
7210
7211impl fmt::Display for CreateEventTrigger {
7212    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7213        write!(f, "CREATE EVENT TRIGGER {} ON {}", self.name, self.event)?;
7214        if let Some(tags) = &self.when_tags {
7215            write!(f, " WHEN TAG IN ({})", display_comma_separated(tags))?;
7216        }
7217        let func_kw = if self.is_procedure {
7218            "PROCEDURE"
7219        } else {
7220            "FUNCTION"
7221        };
7222        write!(f, " EXECUTE {func_kw} {}()", self.execute)?;
7223        Ok(())
7224    }
7225}
7226
7227impl From<CreateUserMapping> for crate::ast::Statement {
7228    fn from(v: CreateUserMapping) -> Self {
7229        crate::ast::Statement::CreateUserMapping(v)
7230    }
7231}
7232
7233/// A `CREATE TABLESPACE` statement.
7234///
7235/// Note: this is a PostgreSQL-specific statement.
7236/// <https://www.postgresql.org/docs/current/sql-createtablespace.html>
7237#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
7238#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7239#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
7240pub struct CreateTablespace {
7241    /// The tablespace name.
7242    pub name: Ident,
7243    /// Optional `OWNER role` clause.
7244    pub owner: Option<Ident>,
7245    /// The `LOCATION 'directory'` string.
7246    pub location: Value,
7247    /// Optional `WITH (option = value, ...)` clause.
7248    pub with_options: Vec<SqlOption>,
7249}
7250
7251impl fmt::Display for CreateTablespace {
7252    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7253        write!(f, "CREATE TABLESPACE {}", self.name)?;
7254        if let Some(owner) = &self.owner {
7255            write!(f, " OWNER {owner}")?;
7256        }
7257        write!(f, " LOCATION {}", self.location)?;
7258        if !self.with_options.is_empty() {
7259            write!(f, " WITH ({})", display_comma_separated(&self.with_options))?;
7260        }
7261        Ok(())
7262    }
7263}
7264
7265impl From<CreateEventTrigger> for crate::ast::Statement {
7266    fn from(v: CreateEventTrigger) -> Self {
7267        crate::ast::Statement::CreateEventTrigger(v)
7268    }
7269}
7270
7271/// A single element in a `CREATE TRANSFORM` transform list.
7272///
7273/// Either `FROM SQL WITH FUNCTION name(arg_types)` or `TO SQL WITH FUNCTION name(arg_types)`.
7274///
7275/// Note: this is a PostgreSQL-specific concept.
7276/// <https://www.postgresql.org/docs/current/sql-createtransform.html>
7277#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
7278#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7279#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
7280pub struct TransformElement {
7281    /// `true` = FROM SQL, `false` = TO SQL
7282    pub is_from: bool,
7283    /// The function name.
7284    pub function: ObjectName,
7285    /// The argument type list (may be empty).
7286    pub arg_types: Vec<DataType>,
7287}
7288
7289impl fmt::Display for TransformElement {
7290    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7291        let direction = if self.is_from { "FROM" } else { "TO" };
7292        write!(
7293            f,
7294            "{direction} SQL WITH FUNCTION {}({})",
7295            self.function,
7296            display_comma_separated(&self.arg_types),
7297        )
7298    }
7299}
7300
7301/// A `CREATE TRANSFORM` statement.
7302///
7303/// Note: this is a PostgreSQL-specific statement.
7304/// <https://www.postgresql.org/docs/current/sql-createtransform.html>
7305#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
7306#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7307#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
7308pub struct CreateTransform {
7309    /// Whether `OR REPLACE` was specified.
7310    pub or_replace: bool,
7311    /// The data type being transformed.
7312    pub type_name: DataType,
7313    /// The procedural language name.
7314    pub language: Ident,
7315    /// The list of transform elements (FROM SQL and/or TO SQL).
7316    pub elements: Vec<TransformElement>,
7317}
7318
7319impl fmt::Display for CreateTransform {
7320    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7321        write!(f, "CREATE")?;
7322        if self.or_replace {
7323            write!(f, " OR REPLACE")?;
7324        }
7325        write!(
7326            f,
7327            " TRANSFORM FOR {} LANGUAGE {} ({})",
7328            self.type_name,
7329            self.language,
7330            display_comma_separated(&self.elements),
7331        )
7332    }
7333}
7334
7335impl From<CreateTransform> for crate::ast::Statement {
7336    fn from(v: CreateTransform) -> Self {
7337        crate::ast::Statement::CreateTransform(v)
7338    }
7339}
7340
7341impl From<CreateTablespace> for crate::ast::Statement {
7342    fn from(v: CreateTablespace) -> Self {
7343        crate::ast::Statement::CreateTablespace(v)
7344    }
7345}