Skip to main content

sqlparser/ast/
ddl.rs

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