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