Skip to main content

sqlparser/ast/
ddl.rs

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