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