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    /// MySQL: `WITH PARSER parser_name`. Only meaningful for FULLTEXT indexes;
1477    /// see <https://dev.mysql.com/doc/refman/8.0/en/create-index.html>.
1478    WithParser(Ident),
1479    /// MySQL: `VISIBLE`.
1480    Visible,
1481    /// MySQL: `INVISIBLE`.
1482    Invisible,
1483}
1484
1485impl fmt::Display for IndexOption {
1486    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1487        match self {
1488            Self::Using(index_type) => write!(f, "USING {index_type}"),
1489            Self::Comment(s) => write!(f, "COMMENT '{s}'"),
1490            Self::WithParser(name) => write!(f, "WITH PARSER {name}"),
1491            Self::Visible => write!(f, "VISIBLE"),
1492            Self::Invisible => write!(f, "INVISIBLE"),
1493        }
1494    }
1495}
1496
1497/// [PostgreSQL] unique index nulls handling option: `[ NULLS [ NOT ] DISTINCT ]`
1498///
1499/// [PostgreSQL]: https://www.postgresql.org/docs/17/sql-altertable.html
1500#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1501#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1502#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1503pub enum NullsDistinctOption {
1504    /// Not specified
1505    None,
1506    /// NULLS DISTINCT
1507    Distinct,
1508    /// NULLS NOT DISTINCT
1509    NotDistinct,
1510}
1511
1512impl fmt::Display for NullsDistinctOption {
1513    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1514        match self {
1515            Self::None => Ok(()),
1516            Self::Distinct => write!(f, " NULLS DISTINCT"),
1517            Self::NotDistinct => write!(f, " NULLS NOT DISTINCT"),
1518        }
1519    }
1520}
1521
1522#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1523#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1524#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1525/// A parameter of a stored procedure or function declaration.
1526pub struct ProcedureParam {
1527    /// Parameter name.
1528    pub name: Ident,
1529    /// Parameter data type.
1530    pub data_type: DataType,
1531    /// Optional mode (`IN`, `OUT`, `INOUT`, etc.).
1532    pub mode: Option<ArgMode>,
1533    /// Optional default expression for the parameter.
1534    pub default: Option<Expr>,
1535}
1536
1537impl fmt::Display for ProcedureParam {
1538    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1539        if let Some(mode) = &self.mode {
1540            if let Some(default) = &self.default {
1541                write!(f, "{mode} {} {} = {}", self.name, self.data_type, default)
1542            } else {
1543                write!(f, "{mode} {} {}", self.name, self.data_type)
1544            }
1545        } else if let Some(default) = &self.default {
1546            write!(f, "{} {} = {}", self.name, self.data_type, default)
1547        } else {
1548            write!(f, "{} {}", self.name, self.data_type)
1549        }
1550    }
1551}
1552
1553/// SQL column definition
1554#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1555#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1556#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1557pub struct ColumnDef {
1558    /// Column name.
1559    pub name: Ident,
1560    /// Column data type.
1561    pub data_type: DataType,
1562    /// Column options (defaults, constraints, generated, etc.).
1563    pub options: Vec<ColumnOptionDef>,
1564}
1565
1566impl fmt::Display for ColumnDef {
1567    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1568        if self.data_type == DataType::Unspecified {
1569            write!(f, "{}", self.name)?;
1570        } else {
1571            write!(f, "{} {}", self.name, self.data_type)?;
1572        }
1573        for option in &self.options {
1574            write!(f, " {option}")?;
1575        }
1576        Ok(())
1577    }
1578}
1579
1580/// Column definition specified in a `CREATE VIEW` statement.
1581///
1582/// Syntax
1583/// ```markdown
1584/// <name> [data_type][OPTIONS(option, ...)]
1585///
1586/// option: <name> = <value>
1587/// ```
1588///
1589/// Examples:
1590/// ```sql
1591/// name
1592/// age OPTIONS(description = "age column", tag = "prod")
1593/// amount COMMENT 'The total amount for the order line'
1594/// created_at DateTime64
1595/// ```
1596#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1597#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1598#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1599pub struct ViewColumnDef {
1600    /// Column identifier.
1601    pub name: Ident,
1602    /// Optional data type for the column.
1603    pub data_type: Option<DataType>,
1604    /// Optional column options (defaults, comments, etc.).
1605    pub options: Option<ColumnOptions>,
1606}
1607
1608#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1609#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1610#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1611/// Representation of how multiple `ColumnOption`s are grouped for a column.
1612pub enum ColumnOptions {
1613    /// Options separated by comma: `OPTIONS(a, b, c)`.
1614    CommaSeparated(Vec<ColumnOption>),
1615    /// Options separated by spaces: `OPTION_A OPTION_B`.
1616    SpaceSeparated(Vec<ColumnOption>),
1617}
1618
1619impl ColumnOptions {
1620    /// Get the column options as a slice.
1621    pub fn as_slice(&self) -> &[ColumnOption] {
1622        match self {
1623            ColumnOptions::CommaSeparated(options) => options.as_slice(),
1624            ColumnOptions::SpaceSeparated(options) => options.as_slice(),
1625        }
1626    }
1627}
1628
1629impl fmt::Display for ViewColumnDef {
1630    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1631        write!(f, "{}", self.name)?;
1632        if let Some(data_type) = self.data_type.as_ref() {
1633            write!(f, " {data_type}")?;
1634        }
1635        if let Some(options) = self.options.as_ref() {
1636            match options {
1637                ColumnOptions::CommaSeparated(column_options) => {
1638                    write!(f, " {}", display_comma_separated(column_options.as_slice()))?;
1639                }
1640                ColumnOptions::SpaceSeparated(column_options) => {
1641                    write!(f, " {}", display_separated(column_options.as_slice(), " "))?
1642                }
1643            }
1644        }
1645        Ok(())
1646    }
1647}
1648
1649/// An optionally-named `ColumnOption`: `[ CONSTRAINT <name> ] <column-option>`.
1650///
1651/// Note that implementations are substantially more permissive than the ANSI
1652/// specification on what order column options can be presented in, and whether
1653/// they are allowed to be named. The specification distinguishes between
1654/// constraints (NOT NULL, UNIQUE, PRIMARY KEY, and CHECK), which can be named
1655/// and can appear in any order, and other options (DEFAULT, GENERATED), which
1656/// cannot be named and must appear in a fixed order. `PostgreSQL`, however,
1657/// allows preceding any option with `CONSTRAINT <name>`, even those that are
1658/// not really constraints, like NULL and DEFAULT. MSSQL is less permissive,
1659/// allowing DEFAULT, UNIQUE, PRIMARY KEY and CHECK to be named, but not NULL or
1660/// NOT NULL constraints (the last of which is in violation of the spec).
1661///
1662/// For maximum flexibility, we don't distinguish between constraint and
1663/// non-constraint options, lumping them all together under the umbrella of
1664/// "column options," and we allow any column option to be named.
1665#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1666#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1667#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1668pub struct ColumnOptionDef {
1669    /// Optional name of the constraint.
1670    pub name: Option<Ident>,
1671    /// The actual column option (e.g. `NOT NULL`, `DEFAULT`, `GENERATED`, ...).
1672    pub option: ColumnOption,
1673}
1674
1675impl fmt::Display for ColumnOptionDef {
1676    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1677        write!(f, "{}{}", display_constraint_name(&self.name), self.option)
1678    }
1679}
1680
1681/// Identity is a column option for defining an identity or autoincrement column in a `CREATE TABLE` statement.
1682/// Syntax
1683/// ```sql
1684/// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1685/// ```
1686/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1687/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1688#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1689#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1690#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1691pub enum IdentityPropertyKind {
1692    /// An identity property declared via the `AUTOINCREMENT` key word
1693    /// Example:
1694    /// ```sql
1695    ///  AUTOINCREMENT(100, 1) NOORDER
1696    ///  AUTOINCREMENT START 100 INCREMENT 1 ORDER
1697    /// ```
1698    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1699    Autoincrement(IdentityProperty),
1700    /// An identity property declared via the `IDENTITY` key word
1701    /// Example, [MS SQL Server] or [Snowflake]:
1702    /// ```sql
1703    ///  IDENTITY(100, 1)
1704    /// ```
1705    /// [Snowflake]
1706    /// ```sql
1707    ///  IDENTITY(100, 1) ORDER
1708    ///  IDENTITY START 100 INCREMENT 1 NOORDER
1709    /// ```
1710    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1711    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1712    Identity(IdentityProperty),
1713}
1714
1715impl fmt::Display for IdentityPropertyKind {
1716    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1717        let (command, property) = match self {
1718            IdentityPropertyKind::Identity(property) => ("IDENTITY", property),
1719            IdentityPropertyKind::Autoincrement(property) => ("AUTOINCREMENT", property),
1720        };
1721        write!(f, "{command}")?;
1722        if let Some(parameters) = &property.parameters {
1723            write!(f, "{parameters}")?;
1724        }
1725        if let Some(order) = &property.order {
1726            write!(f, "{order}")?;
1727        }
1728        Ok(())
1729    }
1730}
1731
1732/// Properties for the `IDENTITY` / `AUTOINCREMENT` column option.
1733#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1734#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1735#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1736pub struct IdentityProperty {
1737    /// Optional parameters specifying seed/increment for the identity column.
1738    pub parameters: Option<IdentityPropertyFormatKind>,
1739    /// Optional ordering specifier (`ORDER` / `NOORDER`).
1740    pub order: Option<IdentityPropertyOrder>,
1741}
1742
1743/// A format of parameters of identity column.
1744///
1745/// It is [Snowflake] specific.
1746/// Syntax
1747/// ```sql
1748/// (seed , increment) | START num INCREMENT num
1749/// ```
1750/// [MS SQL Server] uses one way of representing these parameters.
1751/// Syntax
1752/// ```sql
1753/// (seed , increment)
1754/// ```
1755/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1756/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1757#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1758#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1759#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1760pub enum IdentityPropertyFormatKind {
1761    /// A parameters of identity column declared like parameters of function call
1762    /// Example:
1763    /// ```sql
1764    ///  (100, 1)
1765    /// ```
1766    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1767    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1768    FunctionCall(IdentityParameters),
1769    /// A parameters of identity column declared with keywords `START` and `INCREMENT`
1770    /// Example:
1771    /// ```sql
1772    ///  START 100 INCREMENT 1
1773    /// ```
1774    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1775    StartAndIncrement(IdentityParameters),
1776}
1777
1778impl fmt::Display for IdentityPropertyFormatKind {
1779    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1780        match self {
1781            IdentityPropertyFormatKind::FunctionCall(parameters) => {
1782                write!(f, "({}, {})", parameters.seed, parameters.increment)
1783            }
1784            IdentityPropertyFormatKind::StartAndIncrement(parameters) => {
1785                write!(
1786                    f,
1787                    " START {} INCREMENT {}",
1788                    parameters.seed, parameters.increment
1789                )
1790            }
1791        }
1792    }
1793}
1794/// Parameters specifying seed and increment for identity columns.
1795#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1796#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1797#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1798pub struct IdentityParameters {
1799    /// The initial seed expression for the identity column.
1800    pub seed: Expr,
1801    /// The increment expression for the identity column.
1802    pub increment: Expr,
1803}
1804
1805/// The identity column option specifies how values are generated for the auto-incremented column, either in increasing or decreasing order.
1806/// Syntax
1807/// ```sql
1808/// ORDER | NOORDER
1809/// ```
1810/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1811#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1812#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1813#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1814pub enum IdentityPropertyOrder {
1815    /// `ORDER` - preserve ordering for generated values (where supported).
1816    Order,
1817    /// `NOORDER` - do not enforce ordering for generated values.
1818    NoOrder,
1819}
1820
1821impl fmt::Display for IdentityPropertyOrder {
1822    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1823        match self {
1824            IdentityPropertyOrder::Order => write!(f, " ORDER"),
1825            IdentityPropertyOrder::NoOrder => write!(f, " NOORDER"),
1826        }
1827    }
1828}
1829
1830/// Column policy that identify a security policy of access to a column.
1831/// Syntax
1832/// ```sql
1833/// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1834/// [ WITH ] PROJECTION POLICY <policy_name>
1835/// ```
1836/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1837#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1838#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1839#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1840pub enum ColumnPolicy {
1841    /// `MASKING POLICY (<property>)`
1842    MaskingPolicy(ColumnPolicyProperty),
1843    /// `PROJECTION POLICY (<property>)`
1844    ProjectionPolicy(ColumnPolicyProperty),
1845}
1846
1847impl fmt::Display for ColumnPolicy {
1848    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1849        let (command, property) = match self {
1850            ColumnPolicy::MaskingPolicy(property) => ("MASKING POLICY", property),
1851            ColumnPolicy::ProjectionPolicy(property) => ("PROJECTION POLICY", property),
1852        };
1853        if property.with {
1854            write!(f, "WITH ")?;
1855        }
1856        write!(f, "{command} {}", property.policy_name)?;
1857        if let Some(using_columns) = &property.using_columns {
1858            write!(f, " USING ({})", display_comma_separated(using_columns))?;
1859        }
1860        Ok(())
1861    }
1862}
1863
1864#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1865#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1866#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1867/// Properties describing a column policy (masking or projection).
1868pub struct ColumnPolicyProperty {
1869    /// This flag indicates that the column policy option is declared using the `WITH` prefix.
1870    /// Example
1871    /// ```sql
1872    /// WITH PROJECTION POLICY sample_policy
1873    /// ```
1874    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1875    pub with: bool,
1876    /// The name of the policy to apply to the column.
1877    pub policy_name: ObjectName,
1878    /// Optional list of column identifiers referenced by the policy.
1879    pub using_columns: Option<Vec<Ident>>,
1880}
1881
1882/// Tags option of column
1883/// Syntax
1884/// ```sql
1885/// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1886/// ```
1887/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1888#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1889#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1890#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1891pub struct TagsColumnOption {
1892    /// This flag indicates that the tags option is declared using the `WITH` prefix.
1893    /// Example:
1894    /// ```sql
1895    /// WITH TAG (A = 'Tag A')
1896    /// ```
1897    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1898    pub with: bool,
1899    /// List of tags to attach to the column.
1900    pub tags: Vec<Tag>,
1901}
1902
1903impl fmt::Display for TagsColumnOption {
1904    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1905        if self.with {
1906            write!(f, "WITH ")?;
1907        }
1908        write!(f, "TAG ({})", display_comma_separated(&self.tags))?;
1909        Ok(())
1910    }
1911}
1912
1913/// `ColumnOption`s are modifiers that follow a column definition in a `CREATE
1914/// TABLE` statement.
1915#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1916#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1917#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1918pub enum ColumnOption {
1919    /// `NULL`
1920    Null,
1921    /// `NOT NULL`
1922    NotNull,
1923    /// `DEFAULT <restricted-expr>`
1924    Default(Expr),
1925
1926    /// `MATERIALIZE <expr>`
1927    /// Syntax: `b INT MATERIALIZE (a + 1)`
1928    ///
1929    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1930    Materialized(Expr),
1931    /// `EPHEMERAL [<expr>]`
1932    ///
1933    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1934    Ephemeral(Option<Expr>),
1935    /// `ALIAS <expr>`
1936    ///
1937    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1938    Alias(Expr),
1939
1940    /// `PRIMARY KEY [<constraint_characteristics>]`
1941    PrimaryKey(PrimaryKeyConstraint),
1942    /// `UNIQUE [<constraint_characteristics>]`
1943    Unique(UniqueConstraint),
1944    /// A referential integrity constraint (`REFERENCES <foreign_table> (<referred_columns>)
1945    /// [ MATCH { FULL | PARTIAL | SIMPLE } ]
1946    /// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
1947    ///   [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
1948    /// }
1949    /// [<constraint_characteristics>]
1950    /// `).
1951    ForeignKey(ForeignKeyConstraint),
1952    /// `CHECK (<expr>)`
1953    Check(CheckConstraint),
1954    /// Dialect-specific options, such as:
1955    /// - MySQL's `AUTO_INCREMENT` or SQLite's `AUTOINCREMENT`
1956    /// - ...
1957    DialectSpecific(Vec<Token>),
1958    /// `CHARACTER SET <name>` column option
1959    CharacterSet(ObjectName),
1960    /// `COLLATE <name>` column option
1961    Collation(ObjectName),
1962    /// `COMMENT '<text>'` column option
1963    Comment(String),
1964    /// `ON UPDATE <expr>` column option
1965    OnUpdate(Expr),
1966    /// `Generated`s are modifiers that follow a column definition in a `CREATE
1967    /// TABLE` statement.
1968    Generated {
1969        /// How the column is generated (e.g. `GENERATED ALWAYS`, `BY DEFAULT`, or expression-stored).
1970        generated_as: GeneratedAs,
1971        /// Sequence/identity options when generation is backed by a sequence.
1972        sequence_options: Option<Vec<SequenceOptions>>,
1973        /// Optional expression used to generate the column value.
1974        generation_expr: Option<Expr>,
1975        /// Mode of the generated expression (`VIRTUAL` or `STORED`) when `generation_expr` is present.
1976        generation_expr_mode: Option<GeneratedExpressionMode>,
1977        /// false if 'GENERATED ALWAYS' is skipped (option starts with AS)
1978        generated_keyword: bool,
1979    },
1980    /// BigQuery specific: Explicit column options in a view [1] or table [2]
1981    /// Syntax
1982    /// ```sql
1983    /// OPTIONS(description="field desc")
1984    /// ```
1985    /// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#view_column_option_list
1986    /// [2]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#column_option_list
1987    Options(Vec<SqlOption>),
1988    /// Creates an identity or an autoincrement column in a table.
1989    /// Syntax
1990    /// ```sql
1991    /// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1992    /// ```
1993    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1994    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1995    Identity(IdentityPropertyKind),
1996    /// SQLite specific: ON CONFLICT option on column definition
1997    /// <https://www.sqlite.org/lang_conflict.html>
1998    OnConflict(Keyword),
1999    /// Snowflake specific: an option of specifying security masking or projection policy to set on a column.
2000    /// Syntax:
2001    /// ```sql
2002    /// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
2003    /// [ WITH ] PROJECTION POLICY <policy_name>
2004    /// ```
2005    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
2006    Policy(ColumnPolicy),
2007    /// Snowflake specific: Specifies the tag name and the tag string value.
2008    /// Syntax:
2009    /// ```sql
2010    /// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
2011    /// ```
2012    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
2013    Tags(TagsColumnOption),
2014    /// MySQL specific: Spatial reference identifier
2015    /// Syntax:
2016    /// ```sql
2017    /// CREATE TABLE geom (g GEOMETRY NOT NULL SRID 4326);
2018    /// ```
2019    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/creating-spatial-indexes.html
2020    Srid(Box<Expr>),
2021    /// MySQL specific: Column is invisible via SELECT *
2022    /// Syntax:
2023    /// ```sql
2024    /// CREATE TABLE t (foo INT, bar INT INVISIBLE);
2025    /// ```
2026    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/invisible-columns.html
2027    Invisible,
2028}
2029
2030impl From<UniqueConstraint> for ColumnOption {
2031    fn from(c: UniqueConstraint) -> Self {
2032        ColumnOption::Unique(c)
2033    }
2034}
2035
2036impl From<PrimaryKeyConstraint> for ColumnOption {
2037    fn from(c: PrimaryKeyConstraint) -> Self {
2038        ColumnOption::PrimaryKey(c)
2039    }
2040}
2041
2042impl From<CheckConstraint> for ColumnOption {
2043    fn from(c: CheckConstraint) -> Self {
2044        ColumnOption::Check(c)
2045    }
2046}
2047impl From<ForeignKeyConstraint> for ColumnOption {
2048    fn from(fk: ForeignKeyConstraint) -> Self {
2049        ColumnOption::ForeignKey(fk)
2050    }
2051}
2052
2053impl fmt::Display for ColumnOption {
2054    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2055        use ColumnOption::*;
2056        match self {
2057            Null => write!(f, "NULL"),
2058            NotNull => write!(f, "NOT NULL"),
2059            Default(expr) => write!(f, "DEFAULT {expr}"),
2060            Materialized(expr) => write!(f, "MATERIALIZED {expr}"),
2061            Ephemeral(expr) => {
2062                if let Some(e) = expr {
2063                    write!(f, "EPHEMERAL {e}")
2064                } else {
2065                    write!(f, "EPHEMERAL")
2066                }
2067            }
2068            Alias(expr) => write!(f, "ALIAS {expr}"),
2069            PrimaryKey(constraint) => {
2070                write!(f, "PRIMARY KEY")?;
2071                if let Some(characteristics) = &constraint.characteristics {
2072                    write!(f, " {characteristics}")?;
2073                }
2074                Ok(())
2075            }
2076            Unique(constraint) => {
2077                write!(f, "UNIQUE{:>}", constraint.index_type_display)?;
2078                if let Some(characteristics) = &constraint.characteristics {
2079                    write!(f, " {characteristics}")?;
2080                }
2081                Ok(())
2082            }
2083            ForeignKey(constraint) => {
2084                write!(f, "REFERENCES {}", constraint.foreign_table)?;
2085                if !constraint.referred_columns.is_empty() {
2086                    write!(
2087                        f,
2088                        " ({})",
2089                        display_comma_separated(&constraint.referred_columns)
2090                    )?;
2091                }
2092                if let Some(match_kind) = &constraint.match_kind {
2093                    write!(f, " {match_kind}")?;
2094                }
2095                if let Some(action) = &constraint.on_delete {
2096                    write!(f, " ON DELETE {action}")?;
2097                }
2098                if let Some(action) = &constraint.on_update {
2099                    write!(f, " ON UPDATE {action}")?;
2100                }
2101                if let Some(characteristics) = &constraint.characteristics {
2102                    write!(f, " {characteristics}")?;
2103                }
2104                Ok(())
2105            }
2106            Check(constraint) => write!(f, "{constraint}"),
2107            DialectSpecific(val) => write!(f, "{}", display_separated(val, " ")),
2108            CharacterSet(n) => write!(f, "CHARACTER SET {n}"),
2109            Collation(n) => write!(f, "COLLATE {n}"),
2110            Comment(v) => write!(f, "COMMENT '{}'", escape_single_quote_string(v)),
2111            OnUpdate(expr) => write!(f, "ON UPDATE {expr}"),
2112            Generated {
2113                generated_as,
2114                sequence_options,
2115                generation_expr,
2116                generation_expr_mode,
2117                generated_keyword,
2118            } => {
2119                if let Some(expr) = generation_expr {
2120                    let modifier = match generation_expr_mode {
2121                        None => "",
2122                        Some(GeneratedExpressionMode::Virtual) => " VIRTUAL",
2123                        Some(GeneratedExpressionMode::Stored) => " STORED",
2124                    };
2125                    if *generated_keyword {
2126                        write!(f, "GENERATED ALWAYS AS ({expr}){modifier}")?;
2127                    } else {
2128                        write!(f, "AS ({expr}){modifier}")?;
2129                    }
2130                    Ok(())
2131                } else {
2132                    // Like Postgres - generated from sequence
2133                    let when = match generated_as {
2134                        GeneratedAs::Always => "ALWAYS",
2135                        GeneratedAs::ByDefault => "BY DEFAULT",
2136                        // ExpStored goes with an expression, handled above
2137                        GeneratedAs::ExpStored => "",
2138                    };
2139                    write!(f, "GENERATED {when} AS IDENTITY")?;
2140                    if let Some(so) = sequence_options {
2141                        if !so.is_empty() {
2142                            write!(f, " (")?;
2143                        }
2144                        for sequence_option in so {
2145                            write!(f, "{sequence_option}")?;
2146                        }
2147                        if !so.is_empty() {
2148                            write!(f, " )")?;
2149                        }
2150                    }
2151                    Ok(())
2152                }
2153            }
2154            Options(options) => {
2155                write!(f, "OPTIONS({})", display_comma_separated(options))
2156            }
2157            Identity(parameters) => {
2158                write!(f, "{parameters}")
2159            }
2160            OnConflict(keyword) => {
2161                write!(f, "ON CONFLICT {keyword:?}")?;
2162                Ok(())
2163            }
2164            Policy(parameters) => {
2165                write!(f, "{parameters}")
2166            }
2167            Tags(tags) => {
2168                write!(f, "{tags}")
2169            }
2170            Srid(srid) => {
2171                write!(f, "SRID {srid}")
2172            }
2173            Invisible => {
2174                write!(f, "INVISIBLE")
2175            }
2176        }
2177    }
2178}
2179
2180/// `GeneratedAs`s are modifiers that follow a column option in a `generated`.
2181/// 'ExpStored' is used for a column generated from an expression and stored.
2182#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
2183#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2184#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2185pub enum GeneratedAs {
2186    /// `GENERATED ALWAYS`
2187    Always,
2188    /// `GENERATED BY DEFAULT`
2189    ByDefault,
2190    /// Expression-based generated column that is stored (used internally for expression-stored columns)
2191    ExpStored,
2192}
2193
2194/// `GeneratedExpressionMode`s are modifiers that follow an expression in a `generated`.
2195/// No modifier is typically the same as Virtual.
2196#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
2197#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2198#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2199pub enum GeneratedExpressionMode {
2200    /// `VIRTUAL` generated expression
2201    Virtual,
2202    /// `STORED` generated expression
2203    Stored,
2204}
2205
2206#[must_use]
2207pub(crate) fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
2208    struct ConstraintName<'a>(&'a Option<Ident>);
2209    impl fmt::Display for ConstraintName<'_> {
2210        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2211            if let Some(name) = self.0 {
2212                write!(f, "CONSTRAINT {name} ")?;
2213            }
2214            Ok(())
2215        }
2216    }
2217    ConstraintName(name)
2218}
2219
2220/// If `option` is
2221/// * `Some(inner)` => create display struct for `"{prefix}{inner}{postfix}"`
2222/// * `_` => do nothing
2223#[must_use]
2224pub(crate) fn display_option<'a, T: fmt::Display>(
2225    prefix: &'a str,
2226    postfix: &'a str,
2227    option: &'a Option<T>,
2228) -> impl fmt::Display + 'a {
2229    struct OptionDisplay<'a, T>(&'a str, &'a str, &'a Option<T>);
2230    impl<T: fmt::Display> fmt::Display for OptionDisplay<'_, T> {
2231        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2232            if let Some(inner) = self.2 {
2233                let (prefix, postfix) = (self.0, self.1);
2234                write!(f, "{prefix}{inner}{postfix}")?;
2235            }
2236            Ok(())
2237        }
2238    }
2239    OptionDisplay(prefix, postfix, option)
2240}
2241
2242/// If `option` is
2243/// * `Some(inner)` => create display struct for `" {inner}"`
2244/// * `_` => do nothing
2245#[must_use]
2246pub(crate) fn display_option_spaced<T: fmt::Display>(option: &Option<T>) -> impl fmt::Display + '_ {
2247    display_option(" ", "", option)
2248}
2249
2250/// `<constraint_characteristics> = [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ]`
2251///
2252/// Used in UNIQUE and foreign key constraints. The individual settings may occur in any order.
2253#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Default, Eq, Ord, Hash)]
2254#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2255#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2256pub struct ConstraintCharacteristics {
2257    /// `[ DEFERRABLE | NOT DEFERRABLE ]`
2258    pub deferrable: Option<bool>,
2259    /// `[ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]`
2260    pub initially: Option<DeferrableInitial>,
2261    /// `[ ENFORCED | NOT ENFORCED ]`
2262    pub enforced: Option<bool>,
2263}
2264
2265/// Initial setting for deferrable constraints (`INITIALLY IMMEDIATE` or `INITIALLY DEFERRED`).
2266#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2267#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2268#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2269pub enum DeferrableInitial {
2270    /// `INITIALLY IMMEDIATE`
2271    Immediate,
2272    /// `INITIALLY DEFERRED`
2273    Deferred,
2274}
2275
2276impl ConstraintCharacteristics {
2277    fn deferrable_text(&self) -> Option<&'static str> {
2278        self.deferrable.map(|deferrable| {
2279            if deferrable {
2280                "DEFERRABLE"
2281            } else {
2282                "NOT DEFERRABLE"
2283            }
2284        })
2285    }
2286
2287    fn initially_immediate_text(&self) -> Option<&'static str> {
2288        self.initially
2289            .map(|initially_immediate| match initially_immediate {
2290                DeferrableInitial::Immediate => "INITIALLY IMMEDIATE",
2291                DeferrableInitial::Deferred => "INITIALLY DEFERRED",
2292            })
2293    }
2294
2295    fn enforced_text(&self) -> Option<&'static str> {
2296        self.enforced.map(
2297            |enforced| {
2298                if enforced {
2299                    "ENFORCED"
2300                } else {
2301                    "NOT ENFORCED"
2302                }
2303            },
2304        )
2305    }
2306}
2307
2308impl fmt::Display for ConstraintCharacteristics {
2309    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2310        let deferrable = self.deferrable_text();
2311        let initially_immediate = self.initially_immediate_text();
2312        let enforced = self.enforced_text();
2313
2314        match (deferrable, initially_immediate, enforced) {
2315            (None, None, None) => Ok(()),
2316            (None, None, Some(enforced)) => write!(f, "{enforced}"),
2317            (None, Some(initial), None) => write!(f, "{initial}"),
2318            (None, Some(initial), Some(enforced)) => write!(f, "{initial} {enforced}"),
2319            (Some(deferrable), None, None) => write!(f, "{deferrable}"),
2320            (Some(deferrable), None, Some(enforced)) => write!(f, "{deferrable} {enforced}"),
2321            (Some(deferrable), Some(initial), None) => write!(f, "{deferrable} {initial}"),
2322            (Some(deferrable), Some(initial), Some(enforced)) => {
2323                write!(f, "{deferrable} {initial} {enforced}")
2324            }
2325        }
2326    }
2327}
2328
2329/// `<referential_action> =
2330/// { RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT }`
2331///
2332/// Used in foreign key constraints in `ON UPDATE` and `ON DELETE` options.
2333#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2334#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2335#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2336pub enum ReferentialAction {
2337    /// `RESTRICT` - disallow action if it would break referential integrity.
2338    Restrict,
2339    /// `CASCADE` - propagate the action to referencing rows.
2340    Cascade,
2341    /// `SET NULL` - set referencing columns to NULL.
2342    SetNull,
2343    /// `NO ACTION` - no action at the time; may be deferred.
2344    NoAction,
2345    /// `SET DEFAULT` - set referencing columns to their default values.
2346    SetDefault,
2347}
2348
2349impl fmt::Display for ReferentialAction {
2350    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2351        f.write_str(match self {
2352            ReferentialAction::Restrict => "RESTRICT",
2353            ReferentialAction::Cascade => "CASCADE",
2354            ReferentialAction::SetNull => "SET NULL",
2355            ReferentialAction::NoAction => "NO ACTION",
2356            ReferentialAction::SetDefault => "SET DEFAULT",
2357        })
2358    }
2359}
2360
2361/// `<drop behavior> ::= CASCADE | RESTRICT`.
2362///
2363/// Used in `DROP` statements.
2364#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2365#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2366#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2367pub enum DropBehavior {
2368    /// `RESTRICT` - refuse to drop if there are any dependent objects.
2369    Restrict,
2370    /// `CASCADE` - automatically drop objects that depend on the object being dropped.
2371    Cascade,
2372}
2373
2374impl fmt::Display for DropBehavior {
2375    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2376        f.write_str(match self {
2377            DropBehavior::Restrict => "RESTRICT",
2378            DropBehavior::Cascade => "CASCADE",
2379        })
2380    }
2381}
2382
2383/// SQL user defined type definition
2384#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2385#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2386#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2387pub enum UserDefinedTypeRepresentation {
2388    /// Composite type: `CREATE TYPE name AS (attributes)`
2389    Composite {
2390        /// List of attributes for the composite type.
2391        attributes: Vec<UserDefinedTypeCompositeAttributeDef>,
2392    },
2393    /// Enum type: `CREATE TYPE name AS ENUM (labels)`
2394    ///
2395    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2396    /// Enum type: `CREATE TYPE name AS ENUM (labels)`
2397    Enum {
2398        /// Labels that make up the enum type.
2399        labels: Vec<Ident>,
2400    },
2401    /// Range type: `CREATE TYPE name AS RANGE (options)`
2402    ///
2403    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2404    Range {
2405        /// Options for the range type definition.
2406        options: Vec<UserDefinedTypeRangeOption>,
2407    },
2408    /// Base type (SQL definition): `CREATE TYPE name (options)`
2409    ///
2410    /// Note the lack of `AS` keyword
2411    ///
2412    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2413    SqlDefinition {
2414        /// Options for SQL definition of the user-defined type.
2415        options: Vec<UserDefinedTypeSqlDefinitionOption>,
2416    },
2417}
2418
2419impl fmt::Display for UserDefinedTypeRepresentation {
2420    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2421        match self {
2422            Self::Composite { attributes } => {
2423                write!(f, "AS ({})", display_comma_separated(attributes))
2424            }
2425            Self::Enum { labels } => {
2426                write!(f, "AS ENUM ({})", display_comma_separated(labels))
2427            }
2428            Self::Range { options } => {
2429                write!(f, "AS RANGE ({})", display_comma_separated(options))
2430            }
2431            Self::SqlDefinition { options } => {
2432                write!(f, "({})", display_comma_separated(options))
2433            }
2434        }
2435    }
2436}
2437
2438/// SQL user defined type attribute definition
2439#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2440#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2441#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2442pub struct UserDefinedTypeCompositeAttributeDef {
2443    /// Attribute name.
2444    pub name: Ident,
2445    /// Attribute data type.
2446    pub data_type: DataType,
2447    /// Optional collation for the attribute.
2448    pub collation: Option<ObjectName>,
2449}
2450
2451impl fmt::Display for UserDefinedTypeCompositeAttributeDef {
2452    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2453        write!(f, "{} {}", self.name, self.data_type)?;
2454        if let Some(collation) = &self.collation {
2455            write!(f, " COLLATE {collation}")?;
2456        }
2457        Ok(())
2458    }
2459}
2460
2461/// Internal length specification for PostgreSQL user-defined base types.
2462///
2463/// Specifies the internal length in bytes of the new type's internal representation.
2464/// The default assumption is that it is variable-length.
2465///
2466/// # PostgreSQL Documentation
2467/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2468///
2469/// # Examples
2470/// ```sql
2471/// CREATE TYPE mytype (
2472///     INPUT = in_func,
2473///     OUTPUT = out_func,
2474///     INTERNALLENGTH = 16  -- Fixed 16-byte length
2475/// );
2476///
2477/// CREATE TYPE mytype2 (
2478///     INPUT = in_func,
2479///     OUTPUT = out_func,
2480///     INTERNALLENGTH = VARIABLE  -- Variable length
2481/// );
2482/// ```
2483#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2484#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2485#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2486pub enum UserDefinedTypeInternalLength {
2487    /// Fixed internal length: `INTERNALLENGTH = <number>`
2488    Fixed(u64),
2489    /// Variable internal length: `INTERNALLENGTH = VARIABLE`
2490    Variable,
2491}
2492
2493impl fmt::Display for UserDefinedTypeInternalLength {
2494    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2495        match self {
2496            UserDefinedTypeInternalLength::Fixed(n) => write!(f, "{}", n),
2497            UserDefinedTypeInternalLength::Variable => write!(f, "VARIABLE"),
2498        }
2499    }
2500}
2501
2502/// Alignment specification for PostgreSQL user-defined base types.
2503///
2504/// Specifies the storage alignment requirement for values of the data type.
2505/// The allowed values equate to alignment on 1, 2, 4, or 8 byte boundaries.
2506/// Note that variable-length types must have an alignment of at least 4, since
2507/// they necessarily contain an int4 as their first component.
2508///
2509/// # PostgreSQL Documentation
2510/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2511///
2512/// # Examples
2513/// ```sql
2514/// CREATE TYPE mytype (
2515///     INPUT = in_func,
2516///     OUTPUT = out_func,
2517///     ALIGNMENT = int4  -- 4-byte alignment
2518/// );
2519/// ```
2520#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2521#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2522#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2523pub enum Alignment {
2524    /// Single-byte alignment: `ALIGNMENT = char`
2525    Char,
2526    /// 2-byte alignment: `ALIGNMENT = int2`
2527    Int2,
2528    /// 4-byte alignment: `ALIGNMENT = int4`
2529    Int4,
2530    /// 8-byte alignment: `ALIGNMENT = double`
2531    Double,
2532}
2533
2534impl fmt::Display for Alignment {
2535    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2536        match self {
2537            Alignment::Char => write!(f, "char"),
2538            Alignment::Int2 => write!(f, "int2"),
2539            Alignment::Int4 => write!(f, "int4"),
2540            Alignment::Double => write!(f, "double"),
2541        }
2542    }
2543}
2544
2545/// Storage specification for PostgreSQL user-defined base types.
2546///
2547/// Specifies the storage strategy for values of the data type:
2548/// - `plain`: Prevents compression and out-of-line storage (for fixed-length types)
2549/// - `external`: Allows out-of-line storage but not compression
2550/// - `extended`: Allows both compression and out-of-line storage (default for most types)
2551/// - `main`: Allows compression but discourages out-of-line storage
2552///
2553/// # PostgreSQL Documentation
2554/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2555///
2556/// # Examples
2557/// ```sql
2558/// CREATE TYPE mytype (
2559///     INPUT = in_func,
2560///     OUTPUT = out_func,
2561///     STORAGE = plain
2562/// );
2563/// ```
2564#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2565#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2566#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2567pub enum UserDefinedTypeStorage {
2568    /// No compression or out-of-line storage: `STORAGE = plain`
2569    Plain,
2570    /// Out-of-line storage allowed, no compression: `STORAGE = external`
2571    External,
2572    /// Both compression and out-of-line storage allowed: `STORAGE = extended`
2573    Extended,
2574    /// Compression allowed, out-of-line discouraged: `STORAGE = main`
2575    Main,
2576}
2577
2578impl fmt::Display for UserDefinedTypeStorage {
2579    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2580        match self {
2581            UserDefinedTypeStorage::Plain => write!(f, "plain"),
2582            UserDefinedTypeStorage::External => write!(f, "external"),
2583            UserDefinedTypeStorage::Extended => write!(f, "extended"),
2584            UserDefinedTypeStorage::Main => write!(f, "main"),
2585        }
2586    }
2587}
2588
2589/// Options for PostgreSQL `CREATE TYPE ... AS RANGE` statement.
2590///
2591/// Range types are data types representing a range of values of some element type
2592/// (called the range's subtype). These options configure the behavior of the range type.
2593///
2594/// # PostgreSQL Documentation
2595/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2596///
2597/// # Examples
2598/// ```sql
2599/// CREATE TYPE int4range AS RANGE (
2600///     SUBTYPE = int4,
2601///     SUBTYPE_OPCLASS = int4_ops,
2602///     CANONICAL = int4range_canonical,
2603///     SUBTYPE_DIFF = int4range_subdiff
2604/// );
2605/// ```
2606#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2607#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2608#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2609pub enum UserDefinedTypeRangeOption {
2610    /// The element type that the range type will represent: `SUBTYPE = subtype`
2611    Subtype(DataType),
2612    /// The operator class for the subtype: `SUBTYPE_OPCLASS = subtype_operator_class`
2613    SubtypeOpClass(ObjectName),
2614    /// Collation to use for ordering the subtype: `COLLATION = collation`
2615    Collation(ObjectName),
2616    /// Function to convert range values to canonical form: `CANONICAL = canonical_function`
2617    Canonical(ObjectName),
2618    /// Function to compute the difference between two subtype values: `SUBTYPE_DIFF = subtype_diff_function`
2619    SubtypeDiff(ObjectName),
2620    /// Name of the corresponding multirange type: `MULTIRANGE_TYPE_NAME = multirange_type_name`
2621    MultirangeTypeName(ObjectName),
2622}
2623
2624impl fmt::Display for UserDefinedTypeRangeOption {
2625    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2626        match self {
2627            UserDefinedTypeRangeOption::Subtype(dt) => write!(f, "SUBTYPE = {}", dt),
2628            UserDefinedTypeRangeOption::SubtypeOpClass(name) => {
2629                write!(f, "SUBTYPE_OPCLASS = {}", name)
2630            }
2631            UserDefinedTypeRangeOption::Collation(name) => write!(f, "COLLATION = {}", name),
2632            UserDefinedTypeRangeOption::Canonical(name) => write!(f, "CANONICAL = {}", name),
2633            UserDefinedTypeRangeOption::SubtypeDiff(name) => write!(f, "SUBTYPE_DIFF = {}", name),
2634            UserDefinedTypeRangeOption::MultirangeTypeName(name) => {
2635                write!(f, "MULTIRANGE_TYPE_NAME = {}", name)
2636            }
2637        }
2638    }
2639}
2640
2641/// Options for PostgreSQL `CREATE TYPE ... (<options>)` statement (base type definition).
2642///
2643/// Base types are the lowest-level data types in PostgreSQL. To define a new base type,
2644/// you must specify functions that convert it to and from text representation, and optionally
2645/// binary representation and other properties.
2646///
2647/// Note: This syntax uses parentheses directly after the type name, without the `AS` keyword.
2648///
2649/// # PostgreSQL Documentation
2650/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2651///
2652/// # Examples
2653/// ```sql
2654/// CREATE TYPE complex (
2655///     INPUT = complex_in,
2656///     OUTPUT = complex_out,
2657///     INTERNALLENGTH = 16,
2658///     ALIGNMENT = double
2659/// );
2660/// ```
2661#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2662#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2663#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2664pub enum UserDefinedTypeSqlDefinitionOption {
2665    /// Function to convert from external text representation to internal: `INPUT = input_function`
2666    Input(ObjectName),
2667    /// Function to convert from internal to external text representation: `OUTPUT = output_function`
2668    Output(ObjectName),
2669    /// Function to convert from external binary representation to internal: `RECEIVE = receive_function`
2670    Receive(ObjectName),
2671    /// Function to convert from internal to external binary representation: `SEND = send_function`
2672    Send(ObjectName),
2673    /// Function to convert type modifiers from text array to internal form: `TYPMOD_IN = type_modifier_input_function`
2674    TypmodIn(ObjectName),
2675    /// Function to convert type modifiers from internal to text form: `TYPMOD_OUT = type_modifier_output_function`
2676    TypmodOut(ObjectName),
2677    /// Function to compute statistics for the data type: `ANALYZE = analyze_function`
2678    Analyze(ObjectName),
2679    /// Function to handle subscripting operations: `SUBSCRIPT = subscript_function`
2680    Subscript(ObjectName),
2681    /// Internal storage size in bytes, or VARIABLE for variable-length: `INTERNALLENGTH = { internallength | VARIABLE }`
2682    InternalLength(UserDefinedTypeInternalLength),
2683    /// Indicates values are passed by value rather than by reference: `PASSEDBYVALUE`
2684    PassedByValue,
2685    /// Storage alignment requirement (1, 2, 4, or 8 bytes): `ALIGNMENT = alignment`
2686    Alignment(Alignment),
2687    /// Storage strategy for varlena types: `STORAGE = storage`
2688    Storage(UserDefinedTypeStorage),
2689    /// Copy properties from an existing type: `LIKE = like_type`
2690    Like(ObjectName),
2691    /// Type category for implicit casting rules (single char): `CATEGORY = category`
2692    Category(char),
2693    /// Whether this type is preferred within its category: `PREFERRED = preferred`
2694    Preferred(bool),
2695    /// Default value for the type: `DEFAULT = default`
2696    Default(Expr),
2697    /// Element type for array types: `ELEMENT = element`
2698    Element(DataType),
2699    /// Delimiter character for array value display: `DELIMITER = delimiter`
2700    Delimiter(String),
2701    /// Whether the type supports collation: `COLLATABLE = collatable`
2702    Collatable(bool),
2703}
2704
2705impl fmt::Display for UserDefinedTypeSqlDefinitionOption {
2706    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2707        match self {
2708            UserDefinedTypeSqlDefinitionOption::Input(name) => write!(f, "INPUT = {}", name),
2709            UserDefinedTypeSqlDefinitionOption::Output(name) => write!(f, "OUTPUT = {}", name),
2710            UserDefinedTypeSqlDefinitionOption::Receive(name) => write!(f, "RECEIVE = {}", name),
2711            UserDefinedTypeSqlDefinitionOption::Send(name) => write!(f, "SEND = {}", name),
2712            UserDefinedTypeSqlDefinitionOption::TypmodIn(name) => write!(f, "TYPMOD_IN = {}", name),
2713            UserDefinedTypeSqlDefinitionOption::TypmodOut(name) => {
2714                write!(f, "TYPMOD_OUT = {}", name)
2715            }
2716            UserDefinedTypeSqlDefinitionOption::Analyze(name) => write!(f, "ANALYZE = {}", name),
2717            UserDefinedTypeSqlDefinitionOption::Subscript(name) => {
2718                write!(f, "SUBSCRIPT = {}", name)
2719            }
2720            UserDefinedTypeSqlDefinitionOption::InternalLength(len) => {
2721                write!(f, "INTERNALLENGTH = {}", len)
2722            }
2723            UserDefinedTypeSqlDefinitionOption::PassedByValue => write!(f, "PASSEDBYVALUE"),
2724            UserDefinedTypeSqlDefinitionOption::Alignment(align) => {
2725                write!(f, "ALIGNMENT = {}", align)
2726            }
2727            UserDefinedTypeSqlDefinitionOption::Storage(storage) => {
2728                write!(f, "STORAGE = {}", storage)
2729            }
2730            UserDefinedTypeSqlDefinitionOption::Like(name) => write!(f, "LIKE = {}", name),
2731            UserDefinedTypeSqlDefinitionOption::Category(c) => write!(f, "CATEGORY = '{}'", c),
2732            UserDefinedTypeSqlDefinitionOption::Preferred(b) => write!(f, "PREFERRED = {}", b),
2733            UserDefinedTypeSqlDefinitionOption::Default(expr) => write!(f, "DEFAULT = {}", expr),
2734            UserDefinedTypeSqlDefinitionOption::Element(dt) => write!(f, "ELEMENT = {}", dt),
2735            UserDefinedTypeSqlDefinitionOption::Delimiter(s) => {
2736                write!(f, "DELIMITER = '{}'", escape_single_quote_string(s))
2737            }
2738            UserDefinedTypeSqlDefinitionOption::Collatable(b) => write!(f, "COLLATABLE = {}", b),
2739        }
2740    }
2741}
2742
2743/// PARTITION statement used in ALTER TABLE et al. such as in Hive and ClickHouse SQL.
2744/// For example, ClickHouse's OPTIMIZE TABLE supports syntax like PARTITION ID 'partition_id' and PARTITION expr.
2745/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2746#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2747#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2748#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2749pub enum Partition {
2750    /// ClickHouse supports PARTITION ID 'partition_id' syntax.
2751    Identifier(Ident),
2752    /// ClickHouse supports PARTITION expr syntax.
2753    Expr(Expr),
2754    /// ClickHouse supports PART expr which represents physical partition in disk.
2755    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
2756    Part(Expr),
2757    /// Hive supports multiple partitions in PARTITION (part1, part2, ...) syntax.
2758    Partitions(Vec<Expr>),
2759}
2760
2761impl fmt::Display for Partition {
2762    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2763        match self {
2764            Partition::Identifier(id) => write!(f, "PARTITION ID {id}"),
2765            Partition::Expr(expr) => write!(f, "PARTITION {expr}"),
2766            Partition::Part(expr) => write!(f, "PART {expr}"),
2767            Partition::Partitions(partitions) => {
2768                write!(f, "PARTITION ({})", display_comma_separated(partitions))
2769            }
2770        }
2771    }
2772}
2773
2774/// DEDUPLICATE statement used in OPTIMIZE TABLE et al. such as in ClickHouse SQL
2775/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2776#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2777#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2778#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2779pub enum Deduplicate {
2780    /// DEDUPLICATE ALL
2781    All,
2782    /// DEDUPLICATE BY expr
2783    ByExpression(Expr),
2784}
2785
2786impl fmt::Display for Deduplicate {
2787    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2788        match self {
2789            Deduplicate::All => write!(f, "DEDUPLICATE"),
2790            Deduplicate::ByExpression(expr) => write!(f, "DEDUPLICATE BY {expr}"),
2791        }
2792    }
2793}
2794
2795/// Hive supports `CLUSTERED BY` statement in `CREATE TABLE`.
2796/// Syntax: `CLUSTERED BY (col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS`
2797///
2798/// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2799#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2800#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2801#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2802pub struct ClusteredBy {
2803    /// columns used for clustering
2804    pub columns: Vec<Ident>,
2805    /// optional sorted by expressions
2806    pub sorted_by: Option<Vec<OrderByExpr>>,
2807    /// number of buckets
2808    pub num_buckets: Value,
2809}
2810
2811impl fmt::Display for ClusteredBy {
2812    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2813        write!(
2814            f,
2815            "CLUSTERED BY ({})",
2816            display_comma_separated(&self.columns)
2817        )?;
2818        if let Some(ref sorted_by) = self.sorted_by {
2819            write!(f, " SORTED BY ({})", display_comma_separated(sorted_by))?;
2820        }
2821        write!(f, " INTO {} BUCKETS", self.num_buckets)
2822    }
2823}
2824
2825/// CREATE INDEX statement.
2826#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2827#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2828#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2829pub struct CreateIndex {
2830    /// index name
2831    pub name: Option<ObjectName>,
2832    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2833    /// table name
2834    pub table_name: ObjectName,
2835    /// Index type used in the statement. Can also be found inside [`CreateIndex::index_options`]
2836    /// depending on the position of the option within the statement.
2837    pub using: Option<IndexType>,
2838    /// columns included in the index
2839    pub columns: Vec<IndexColumn>,
2840    /// whether the index is unique
2841    pub unique: bool,
2842    /// whether the index is created concurrently
2843    pub concurrently: bool,
2844    /// whether the index is created asynchronously ([DSQL]).
2845    ///
2846    /// [DSQL]: https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-create-index-async.html
2847    pub r#async: bool,
2848    /// IF NOT EXISTS clause
2849    pub if_not_exists: bool,
2850    /// INCLUDE clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2851    pub include: Vec<Ident>,
2852    /// NULLS DISTINCT / NOT DISTINCT clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2853    pub nulls_distinct: Option<bool>,
2854    /// WITH clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2855    pub with: Vec<Expr>,
2856    /// WHERE clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2857    pub predicate: Option<Expr>,
2858    /// Index options: <https://www.postgresql.org/docs/current/sql-createindex.html>
2859    pub index_options: Vec<IndexOption>,
2860    /// [MySQL] allows a subset of options normally used for `ALTER TABLE`:
2861    ///
2862    /// - `ALGORITHM`
2863    /// - `LOCK`
2864    ///
2865    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/create-index.html
2866    pub alter_options: Vec<AlterTableOperation>,
2867    /// MySQL: when this index is a standalone `CREATE FULLTEXT INDEX` or
2868    /// `CREATE SPATIAL INDEX`, records which kind. `None` means a plain
2869    /// `CREATE INDEX` (or `CREATE UNIQUE INDEX` when `unique` is true).
2870    ///
2871    /// [MySQL]: https://dev.mysql.com/doc/refman/8.0/en/create-index.html
2872    pub fulltext_or_spatial: Option<FullTextOrSpatialKind>,
2873}
2874
2875/// MySQL: kind of a standalone `CREATE FULLTEXT INDEX` / `CREATE SPATIAL INDEX`.
2876///
2877/// See [`CreateIndex::fulltext_or_spatial`].
2878#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Copy)]
2879#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2880#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2881pub enum FullTextOrSpatialKind {
2882    /// `CREATE FULLTEXT INDEX ...`
2883    Fulltext,
2884    /// `CREATE SPATIAL INDEX ...`
2885    Spatial,
2886}
2887
2888impl fmt::Display for FullTextOrSpatialKind {
2889    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2890        match self {
2891            FullTextOrSpatialKind::Fulltext => f.write_str("FULLTEXT"),
2892            FullTextOrSpatialKind::Spatial => f.write_str("SPATIAL"),
2893        }
2894    }
2895}
2896
2897impl fmt::Display for CreateIndex {
2898    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2899        let kind_prefix = match self.fulltext_or_spatial {
2900            Some(kind) => format!("{kind} "),
2901            None => String::new(),
2902        };
2903        write!(
2904            f,
2905            "CREATE {kind_prefix}{unique}INDEX {concurrently}{async_}{if_not_exists}",
2906            unique = if self.unique { "UNIQUE " } else { "" },
2907            concurrently = if self.concurrently {
2908                "CONCURRENTLY "
2909            } else {
2910                ""
2911            },
2912            async_ = if self.r#async { "ASYNC " } else { "" },
2913            if_not_exists = if self.if_not_exists {
2914                "IF NOT EXISTS "
2915            } else {
2916                ""
2917            },
2918        )?;
2919        if let Some(value) = &self.name {
2920            write!(f, "{value} ")?;
2921        }
2922        write!(f, "ON {}", self.table_name)?;
2923        if let Some(value) = &self.using {
2924            write!(f, " USING {value} ")?;
2925        }
2926        write!(f, "({})", display_comma_separated(&self.columns))?;
2927        if !self.include.is_empty() {
2928            write!(f, " INCLUDE ({})", display_comma_separated(&self.include))?;
2929        }
2930        if let Some(value) = self.nulls_distinct {
2931            if value {
2932                write!(f, " NULLS DISTINCT")?;
2933            } else {
2934                write!(f, " NULLS NOT DISTINCT")?;
2935            }
2936        }
2937        if !self.with.is_empty() {
2938            write!(f, " WITH ({})", display_comma_separated(&self.with))?;
2939        }
2940        if let Some(predicate) = &self.predicate {
2941            write!(f, " WHERE {predicate}")?;
2942        }
2943        if !self.index_options.is_empty() {
2944            write!(f, " {}", display_separated(&self.index_options, " "))?;
2945        }
2946        if !self.alter_options.is_empty() {
2947            write!(f, " {}", display_separated(&self.alter_options, " "))?;
2948        }
2949        Ok(())
2950    }
2951}
2952
2953/// CREATE TABLE statement.
2954#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2955#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2956#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2957pub struct CreateTable {
2958    /// `OR REPLACE` clause
2959    pub or_replace: bool,
2960    /// `TEMP` or `TEMPORARY` clause
2961    pub temporary: bool,
2962    /// `UNLOGGED` clause
2963    pub unlogged: bool,
2964    /// `EXTERNAL` clause
2965    pub external: bool,
2966    /// `DYNAMIC` clause
2967    pub dynamic: bool,
2968    /// `GLOBAL` clause
2969    pub global: Option<bool>,
2970    /// `IF NOT EXISTS` clause
2971    pub if_not_exists: bool,
2972    /// `TRANSIENT` clause
2973    pub transient: bool,
2974    /// `VOLATILE` clause
2975    pub volatile: bool,
2976    /// `ICEBERG` clause
2977    pub iceberg: bool,
2978    /// `SNAPSHOT` clause
2979    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_snapshot_table_statement>
2980    pub snapshot: bool,
2981    /// Table name
2982    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2983    pub name: ObjectName,
2984    /// Column definitions
2985    pub columns: Vec<ColumnDef>,
2986    /// Table constraints
2987    pub constraints: Vec<TableConstraint>,
2988    /// Hive-specific distribution style
2989    pub hive_distribution: HiveDistributionStyle,
2990    /// Hive-specific formats like `ROW FORMAT DELIMITED` or `ROW FORMAT SERDE 'serde_class' WITH SERDEPROPERTIES (...)`
2991    pub hive_formats: Option<HiveFormat>,
2992    /// Table options
2993    pub table_options: CreateTableOptions,
2994    /// General comment for the table
2995    pub file_format: Option<FileFormat>,
2996    /// Location of the table data
2997    pub location: Option<String>,
2998    /// Query used to populate the table
2999    pub query: Option<Box<Query>>,
3000    /// If the table should be created without a rowid (SQLite)
3001    pub without_rowid: bool,
3002    /// `LIKE` clause
3003    pub like: Option<CreateTableLikeKind>,
3004    /// `CLONE` clause
3005    pub clone: Option<ObjectName>,
3006    /// Table version (for systems that support versioned tables)
3007    pub version: Option<TableVersion>,
3008    /// For Hive dialect, the table comment is after the column definitions without `=`,
3009    /// so the `comment` field is optional and different than the comment field in the general options list.
3010    /// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
3011    pub comment: Option<CommentDef>,
3012    /// ClickHouse "ON COMMIT" clause:
3013    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
3014    pub on_commit: Option<OnCommit>,
3015    /// ClickHouse "ON CLUSTER" clause:
3016    /// <https://clickhouse.com/docs/en/sql-reference/distributed-ddl/>
3017    pub on_cluster: Option<Ident>,
3018    /// ClickHouse "PRIMARY KEY " clause.
3019    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
3020    pub primary_key: Option<Box<Expr>>,
3021    /// ClickHouse "ORDER BY " clause. Note that omitted ORDER BY is different
3022    /// than empty (represented as ()), the latter meaning "no sorting".
3023    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
3024    pub order_by: Option<OneOrManyWithParens<Expr>>,
3025    /// BigQuery: A partition expression for the table.
3026    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#partition_expression>
3027    pub partition_by: Option<Box<Expr>>,
3028    /// BigQuery: Table clustering column list.
3029    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#table_option_list>
3030    /// Snowflake: Table clustering list which contains base column, expressions on base columns.
3031    /// <https://docs.snowflake.com/en/user-guide/tables-clustering-keys#defining-a-clustering-key-for-a-table>
3032    pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
3033    /// Hive: Table clustering column list.
3034    /// <https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable>
3035    pub clustered_by: Option<ClusteredBy>,
3036    /// Postgres `INHERITs` clause, which contains the list of tables from which
3037    /// the new table inherits.
3038    /// <https://www.postgresql.org/docs/current/ddl-inherit.html>
3039    /// <https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-INHERITS>
3040    pub inherits: Option<Vec<ObjectName>>,
3041    /// PostgreSQL `PARTITION OF` clause to create a partition of a parent table.
3042    /// Contains the parent table name.
3043    /// <https://www.postgresql.org/docs/current/sql-createtable.html>
3044    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
3045    pub partition_of: Option<ObjectName>,
3046    /// PostgreSQL partition bound specification for PARTITION OF.
3047    /// <https://www.postgresql.org/docs/current/sql-createtable.html>
3048    pub for_values: Option<ForValues>,
3049    /// SQLite "STRICT" clause.
3050    /// if the "STRICT" table-option keyword is added to the end, after the closing ")",
3051    /// then strict typing rules apply to that table.
3052    pub strict: bool,
3053    /// Snowflake "COPY GRANTS" clause
3054    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3055    pub copy_grants: bool,
3056    /// Snowflake "ENABLE_SCHEMA_EVOLUTION" clause
3057    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3058    pub enable_schema_evolution: Option<bool>,
3059    /// Snowflake "CHANGE_TRACKING" clause
3060    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3061    pub change_tracking: Option<bool>,
3062    /// Snowflake "DATA_RETENTION_TIME_IN_DAYS" clause
3063    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3064    pub data_retention_time_in_days: Option<u64>,
3065    /// Snowflake "MAX_DATA_EXTENSION_TIME_IN_DAYS" clause
3066    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3067    pub max_data_extension_time_in_days: Option<u64>,
3068    /// Snowflake "DEFAULT_DDL_COLLATION" clause
3069    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3070    pub default_ddl_collation: Option<String>,
3071    /// Snowflake "WITH AGGREGATION POLICY" clause
3072    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3073    pub with_aggregation_policy: Option<ObjectName>,
3074    /// Snowflake "WITH ROW ACCESS POLICY" clause
3075    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3076    pub with_row_access_policy: Option<RowAccessPolicy>,
3077    /// Snowflake `WITH STORAGE LIFECYCLE POLICY` clause
3078    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3079    pub with_storage_lifecycle_policy: Option<StorageLifecyclePolicy>,
3080    /// Snowflake "WITH TAG" clause
3081    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
3082    pub with_tags: Option<Vec<Tag>>,
3083    /// Snowflake "EXTERNAL_VOLUME" clause for Iceberg tables
3084    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3085    pub external_volume: Option<String>,
3086    /// `WITH CONNECTION` clause.
3087    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_external_table_statement)
3088    pub with_connection: Option<ObjectName>,
3089    /// Snowflake "BASE_LOCATION" clause for Iceberg tables
3090    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3091    pub base_location: Option<String>,
3092    /// Snowflake "CATALOG" clause for Iceberg tables
3093    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3094    pub catalog: Option<String>,
3095    /// Snowflake "CATALOG_SYNC" clause for Iceberg tables
3096    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3097    pub catalog_sync: Option<String>,
3098    /// Snowflake "STORAGE_SERIALIZATION_POLICY" clause for Iceberg tables
3099    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
3100    pub storage_serialization_policy: Option<StorageSerializationPolicy>,
3101    /// Snowflake "TARGET_LAG" clause for dybamic tables
3102    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3103    pub target_lag: Option<String>,
3104    /// Snowflake "WAREHOUSE" clause for dybamic tables
3105    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3106    pub warehouse: Option<Ident>,
3107    /// Snowflake "REFRESH_MODE" clause for dybamic tables
3108    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3109    pub refresh_mode: Option<RefreshModeKind>,
3110    /// Snowflake "INITIALIZE" clause for dybamic tables
3111    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3112    pub initialize: Option<InitializeKind>,
3113    /// Snowflake "REQUIRE USER" clause for dybamic tables
3114    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
3115    pub require_user: bool,
3116    /// Redshift `DISTSTYLE` option
3117    /// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3118    pub diststyle: Option<DistStyle>,
3119    /// Redshift `DISTKEY` option
3120    /// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3121    pub distkey: Option<Expr>,
3122    /// Redshift `SORTKEY` option
3123    /// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3124    pub sortkey: Option<Vec<Expr>>,
3125    /// Redshift `BACKUP` option: `BACKUP { YES | NO }`
3126    /// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3127    pub backup: Option<bool>,
3128    /// `MULTISET | SET` table-kind prefix.
3129    /// `Some(true)` => `MULTISET`, `Some(false)` => `SET`.
3130    ///
3131    /// [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)
3132    pub multiset: Option<bool>,
3133    /// `FALLBACK` clause.
3134    /// `Some(true)` => `FALLBACK`, `Some(false)` => `NO FALLBACK`
3135    ///
3136    /// [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)
3137    pub fallback: Option<bool>,
3138    /// `WITH DATA` clause on a `CREATE TABLE ... AS` statement.
3139    ///
3140    /// [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)
3141    pub with_data: Option<WithData>,
3142}
3143
3144impl fmt::Display for CreateTable {
3145    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3146        // We want to allow the following options
3147        // Empty column list, allowed by PostgreSQL:
3148        //   `CREATE TABLE t ()`
3149        // No columns provided for CREATE TABLE AS:
3150        //   `CREATE TABLE t AS SELECT a from t2`
3151        // Columns provided for CREATE TABLE AS:
3152        //   `CREATE TABLE t (a INT) AS SELECT a from t2`
3153        write!(
3154            f,
3155            "CREATE {or_replace}{external}{global}{multiset}{temporary}{unlogged}{transient}{volatile}{dynamic}{iceberg}{snapshot}TABLE {if_not_exists}{name}",
3156            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
3157            external = if self.external { "EXTERNAL " } else { "" },
3158            snapshot = if self.snapshot { "SNAPSHOT " } else { "" },
3159            global = self.global
3160                .map(|global| {
3161                    if global {
3162                        "GLOBAL "
3163                    } else {
3164                        "LOCAL "
3165                    }
3166                })
3167                .unwrap_or(""),
3168            if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
3169            multiset = self
3170                .multiset
3171                .map(|m| if m { "MULTISET " } else { "SET " })
3172                .unwrap_or(""),
3173            temporary = if self.temporary { "TEMPORARY " } else { "" },
3174            unlogged = if self.unlogged { "UNLOGGED " } else { "" },
3175            transient = if self.transient { "TRANSIENT " } else { "" },
3176            volatile = if self.volatile { "VOLATILE " } else { "" },
3177            iceberg = if self.iceberg { "ICEBERG " } else { "" },
3178            dynamic = if self.dynamic { "DYNAMIC " } else { "" },
3179            name = self.name,
3180        )?;
3181        if let Some(fallback) = self.fallback {
3182            write!(f, ", {}", if fallback { "FALLBACK" } else { "NO FALLBACK" })?;
3183        }
3184        if let Some(partition_of) = &self.partition_of {
3185            write!(f, " PARTITION OF {partition_of}")?;
3186        }
3187        if let Some(on_cluster) = &self.on_cluster {
3188            write!(f, " ON CLUSTER {on_cluster}")?;
3189        }
3190        if !self.columns.is_empty() || !self.constraints.is_empty() {
3191            f.write_str(" (")?;
3192            NewLine.fmt(f)?;
3193            Indent(DisplayCommaSeparated(&self.columns)).fmt(f)?;
3194            if !self.columns.is_empty() && !self.constraints.is_empty() {
3195                f.write_str(",")?;
3196                SpaceOrNewline.fmt(f)?;
3197            }
3198            Indent(DisplayCommaSeparated(&self.constraints)).fmt(f)?;
3199            NewLine.fmt(f)?;
3200            f.write_str(")")?;
3201        } else if self.query.is_none()
3202            && self.like.is_none()
3203            && self.clone.is_none()
3204            && self.partition_of.is_none()
3205        {
3206            // PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
3207            f.write_str(" ()")?;
3208        } else if let Some(CreateTableLikeKind::Parenthesized(like_in_columns_list)) = &self.like {
3209            write!(f, " ({like_in_columns_list})")?;
3210        }
3211        if let Some(for_values) = &self.for_values {
3212            write!(f, " {for_values}")?;
3213        }
3214
3215        // Hive table comment should be after column definitions, please refer to:
3216        // [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
3217        if let Some(comment) = &self.comment {
3218            write!(f, " COMMENT '{comment}'")?;
3219        }
3220
3221        // Only for SQLite
3222        if self.without_rowid {
3223            write!(f, " WITHOUT ROWID")?;
3224        }
3225
3226        if let Some(CreateTableLikeKind::Plain(like)) = &self.like {
3227            write!(f, " {like}")?;
3228        }
3229
3230        if let Some(c) = &self.clone {
3231            write!(f, " CLONE {c}")?;
3232        }
3233
3234        if let Some(version) = &self.version {
3235            write!(f, " {version}")?;
3236        }
3237
3238        match &self.hive_distribution {
3239            HiveDistributionStyle::PARTITIONED { columns } => {
3240                write!(f, " PARTITIONED BY ({})", display_comma_separated(columns))?;
3241            }
3242            HiveDistributionStyle::SKEWED {
3243                columns,
3244                on,
3245                stored_as_directories,
3246            } => {
3247                write!(
3248                    f,
3249                    " SKEWED BY ({})) ON ({})",
3250                    display_comma_separated(columns),
3251                    display_comma_separated(on)
3252                )?;
3253                if *stored_as_directories {
3254                    write!(f, " STORED AS DIRECTORIES")?;
3255                }
3256            }
3257            _ => (),
3258        }
3259
3260        if let Some(clustered_by) = &self.clustered_by {
3261            write!(f, " {clustered_by}")?;
3262        }
3263
3264        if let Some(HiveFormat {
3265            row_format,
3266            serde_properties,
3267            storage,
3268            location,
3269        }) = &self.hive_formats
3270        {
3271            match row_format {
3272                Some(HiveRowFormat::SERDE { class }) => write!(f, " ROW FORMAT SERDE '{class}'")?,
3273                Some(HiveRowFormat::DELIMITED { delimiters }) => {
3274                    write!(f, " ROW FORMAT DELIMITED")?;
3275                    if !delimiters.is_empty() {
3276                        write!(f, " {}", display_separated(delimiters, " "))?;
3277                    }
3278                }
3279                None => (),
3280            }
3281            match storage {
3282                Some(HiveIOFormat::IOF {
3283                    input_format,
3284                    output_format,
3285                }) => write!(
3286                    f,
3287                    " STORED AS INPUTFORMAT {input_format} OUTPUTFORMAT {output_format}"
3288                )?,
3289                Some(HiveIOFormat::FileFormat { format }) if !self.external => {
3290                    write!(f, " STORED AS {format}")?
3291                }
3292                Some(HiveIOFormat::Using { format }) => write!(f, " USING {format}")?,
3293                _ => (),
3294            }
3295            if let Some(serde_properties) = serde_properties.as_ref() {
3296                write!(
3297                    f,
3298                    " WITH SERDEPROPERTIES ({})",
3299                    display_comma_separated(serde_properties)
3300                )?;
3301            }
3302            if !self.external {
3303                if let Some(loc) = location {
3304                    write!(f, " LOCATION '{loc}'")?;
3305                }
3306            }
3307        }
3308        if self.external {
3309            if let Some(file_format) = self.file_format {
3310                write!(f, " STORED AS {file_format}")?;
3311            }
3312            if let Some(location) = &self.location {
3313                write!(f, " LOCATION '{location}'")?;
3314            }
3315        }
3316
3317        match &self.table_options {
3318            options @ CreateTableOptions::With(_)
3319            | options @ CreateTableOptions::Plain(_)
3320            | options @ CreateTableOptions::TableProperties(_) => write!(f, " {options}")?,
3321            _ => (),
3322        }
3323
3324        if let Some(primary_key) = &self.primary_key {
3325            write!(f, " PRIMARY KEY {primary_key}")?;
3326        }
3327        if let Some(order_by) = &self.order_by {
3328            write!(f, " ORDER BY {order_by}")?;
3329        }
3330        if let Some(inherits) = &self.inherits {
3331            write!(f, " INHERITS ({})", display_comma_separated(inherits))?;
3332        }
3333        if let Some(partition_by) = self.partition_by.as_ref() {
3334            write!(f, " PARTITION BY {partition_by}")?;
3335        }
3336        if let Some(cluster_by) = self.cluster_by.as_ref() {
3337            write!(f, " CLUSTER BY {cluster_by}")?;
3338        }
3339        if let Some(with_connection) = &self.with_connection {
3340            write!(f, " WITH CONNECTION {with_connection}")?;
3341        }
3342        if let options @ CreateTableOptions::Options(_) = &self.table_options {
3343            write!(f, " {options}")?;
3344        }
3345        if let Some(external_volume) = self.external_volume.as_ref() {
3346            write!(f, " EXTERNAL_VOLUME='{external_volume}'")?;
3347        }
3348
3349        if let Some(catalog) = self.catalog.as_ref() {
3350            write!(f, " CATALOG='{catalog}'")?;
3351        }
3352
3353        if self.iceberg {
3354            if let Some(base_location) = self.base_location.as_ref() {
3355                write!(f, " BASE_LOCATION='{base_location}'")?;
3356            }
3357        }
3358
3359        if let Some(catalog_sync) = self.catalog_sync.as_ref() {
3360            write!(f, " CATALOG_SYNC='{catalog_sync}'")?;
3361        }
3362
3363        if let Some(storage_serialization_policy) = self.storage_serialization_policy.as_ref() {
3364            write!(
3365                f,
3366                " STORAGE_SERIALIZATION_POLICY={storage_serialization_policy}"
3367            )?;
3368        }
3369
3370        if self.copy_grants {
3371            write!(f, " COPY GRANTS")?;
3372        }
3373
3374        if let Some(is_enabled) = self.enable_schema_evolution {
3375            write!(
3376                f,
3377                " ENABLE_SCHEMA_EVOLUTION={}",
3378                if is_enabled { "TRUE" } else { "FALSE" }
3379            )?;
3380        }
3381
3382        if let Some(is_enabled) = self.change_tracking {
3383            write!(
3384                f,
3385                " CHANGE_TRACKING={}",
3386                if is_enabled { "TRUE" } else { "FALSE" }
3387            )?;
3388        }
3389
3390        if let Some(data_retention_time_in_days) = self.data_retention_time_in_days {
3391            write!(
3392                f,
3393                " DATA_RETENTION_TIME_IN_DAYS={data_retention_time_in_days}",
3394            )?;
3395        }
3396
3397        if let Some(max_data_extension_time_in_days) = self.max_data_extension_time_in_days {
3398            write!(
3399                f,
3400                " MAX_DATA_EXTENSION_TIME_IN_DAYS={max_data_extension_time_in_days}",
3401            )?;
3402        }
3403
3404        if let Some(default_ddl_collation) = &self.default_ddl_collation {
3405            write!(f, " DEFAULT_DDL_COLLATION='{default_ddl_collation}'",)?;
3406        }
3407
3408        if let Some(with_aggregation_policy) = &self.with_aggregation_policy {
3409            write!(f, " WITH AGGREGATION POLICY {with_aggregation_policy}",)?;
3410        }
3411
3412        if let Some(row_access_policy) = &self.with_row_access_policy {
3413            write!(f, " {row_access_policy}",)?;
3414        }
3415
3416        if let Some(storage_lifecycle_policy) = &self.with_storage_lifecycle_policy {
3417            write!(f, " {storage_lifecycle_policy}",)?;
3418        }
3419
3420        if let Some(tag) = &self.with_tags {
3421            write!(f, " WITH TAG ({})", display_comma_separated(tag.as_slice()))?;
3422        }
3423
3424        if let Some(target_lag) = &self.target_lag {
3425            write!(f, " TARGET_LAG='{target_lag}'")?;
3426        }
3427
3428        if let Some(warehouse) = &self.warehouse {
3429            write!(f, " WAREHOUSE={warehouse}")?;
3430        }
3431
3432        if let Some(refresh_mode) = &self.refresh_mode {
3433            write!(f, " REFRESH_MODE={refresh_mode}")?;
3434        }
3435
3436        if let Some(initialize) = &self.initialize {
3437            write!(f, " INITIALIZE={initialize}")?;
3438        }
3439
3440        if self.require_user {
3441            write!(f, " REQUIRE USER")?;
3442        }
3443
3444        if self.on_commit.is_some() {
3445            let on_commit = match self.on_commit {
3446                Some(OnCommit::DeleteRows) => "ON COMMIT DELETE ROWS",
3447                Some(OnCommit::PreserveRows) => "ON COMMIT PRESERVE ROWS",
3448                Some(OnCommit::Drop) => "ON COMMIT DROP",
3449                None => "",
3450            };
3451            write!(f, " {on_commit}")?;
3452        }
3453        if self.strict {
3454            write!(f, " STRICT")?;
3455        }
3456        if let Some(backup) = self.backup {
3457            write!(f, " BACKUP {}", if backup { "YES" } else { "NO" })?;
3458        }
3459        if let Some(diststyle) = &self.diststyle {
3460            write!(f, " DISTSTYLE {diststyle}")?;
3461        }
3462        if let Some(distkey) = &self.distkey {
3463            write!(f, " DISTKEY({distkey})")?;
3464        }
3465        if let Some(sortkey) = &self.sortkey {
3466            write!(f, " SORTKEY({})", display_comma_separated(sortkey))?;
3467        }
3468        if let Some(query) = &self.query {
3469            write!(f, " AS {query}")?;
3470        }
3471        if let Some(with_data) = &self.with_data {
3472            write!(f, " {with_data}")?;
3473        }
3474        Ok(())
3475    }
3476}
3477
3478/// `WITH DATA` clause on `CREATE TABLE ... AS` statement.
3479///
3480/// [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)
3481#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
3482#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3483#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3484pub struct WithData {
3485    /// `true` for `WITH DATA`, `false` for `WITH NO DATA`.
3486    pub data: bool,
3487    /// `Some(true)` for `AND STATISTICS`, `Some(false)` for `AND NO STATISTICS`,
3488    /// `None` if the `AND [NO] STATISTICS` sub-clause is omitted.
3489    pub statistics: Option<bool>,
3490}
3491
3492impl fmt::Display for WithData {
3493    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3494        f.write_str("WITH ")?;
3495        if !self.data {
3496            f.write_str("NO ")?;
3497        }
3498        f.write_str("DATA")?;
3499        if let Some(stats) = self.statistics {
3500            f.write_str(" AND ")?;
3501            if !stats {
3502                f.write_str("NO ")?;
3503            }
3504            f.write_str("STATISTICS")?;
3505        }
3506        Ok(())
3507    }
3508}
3509
3510/// PostgreSQL partition bound specification for `PARTITION OF`.
3511///
3512/// Specifies partition bounds for a child partition table.
3513///
3514/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createtable.html)
3515#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3516#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3517#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3518pub enum ForValues {
3519    /// `FOR VALUES IN (expr, ...)`
3520    In(Vec<Expr>),
3521    /// `FOR VALUES FROM (expr|MINVALUE|MAXVALUE, ...) TO (expr|MINVALUE|MAXVALUE, ...)`
3522    From {
3523        /// The lower bound values for the partition.
3524        from: Vec<PartitionBoundValue>,
3525        /// The upper bound values for the partition.
3526        to: Vec<PartitionBoundValue>,
3527    },
3528    /// `FOR VALUES WITH (MODULUS n, REMAINDER r)`
3529    With {
3530        /// The modulus value for hash partitioning.
3531        modulus: u64,
3532        /// The remainder value for hash partitioning.
3533        remainder: u64,
3534    },
3535    /// `DEFAULT`
3536    Default,
3537}
3538
3539impl fmt::Display for ForValues {
3540    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3541        match self {
3542            ForValues::In(values) => {
3543                write!(f, "FOR VALUES IN ({})", display_comma_separated(values))
3544            }
3545            ForValues::From { from, to } => {
3546                write!(
3547                    f,
3548                    "FOR VALUES FROM ({}) TO ({})",
3549                    display_comma_separated(from),
3550                    display_comma_separated(to)
3551                )
3552            }
3553            ForValues::With { modulus, remainder } => {
3554                write!(
3555                    f,
3556                    "FOR VALUES WITH (MODULUS {modulus}, REMAINDER {remainder})"
3557                )
3558            }
3559            ForValues::Default => write!(f, "DEFAULT"),
3560        }
3561    }
3562}
3563
3564/// A value in a partition bound specification.
3565///
3566/// Used in RANGE partition bounds where values can be expressions,
3567/// MINVALUE (negative infinity), or MAXVALUE (positive infinity).
3568#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3569#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3570#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3571pub enum PartitionBoundValue {
3572    /// An expression representing a partition bound value.
3573    Expr(Expr),
3574    /// Represents negative infinity in partition bounds.
3575    MinValue,
3576    /// Represents positive infinity in partition bounds.
3577    MaxValue,
3578}
3579
3580impl fmt::Display for PartitionBoundValue {
3581    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3582        match self {
3583            PartitionBoundValue::Expr(expr) => write!(f, "{expr}"),
3584            PartitionBoundValue::MinValue => write!(f, "MINVALUE"),
3585            PartitionBoundValue::MaxValue => write!(f, "MAXVALUE"),
3586        }
3587    }
3588}
3589
3590/// Redshift distribution style for `CREATE TABLE`.
3591///
3592/// See [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html)
3593#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3594#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3595#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3596pub enum DistStyle {
3597    /// `DISTSTYLE AUTO`
3598    Auto,
3599    /// `DISTSTYLE EVEN`
3600    Even,
3601    /// `DISTSTYLE KEY`
3602    Key,
3603    /// `DISTSTYLE ALL`
3604    All,
3605}
3606
3607impl fmt::Display for DistStyle {
3608    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3609        match self {
3610            DistStyle::Auto => write!(f, "AUTO"),
3611            DistStyle::Even => write!(f, "EVEN"),
3612            DistStyle::Key => write!(f, "KEY"),
3613            DistStyle::All => write!(f, "ALL"),
3614        }
3615    }
3616}
3617
3618#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3619#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3620#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3621/// ```sql
3622/// CREATE DOMAIN name [ AS ] data_type
3623///         [ COLLATE collation ]
3624///         [ DEFAULT expression ]
3625///         [ domain_constraint [ ... ] ]
3626///
3627///     where domain_constraint is:
3628///
3629///     [ CONSTRAINT constraint_name ]
3630///     { NOT NULL | NULL | CHECK (expression) }
3631/// ```
3632/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createdomain.html)
3633pub struct CreateDomain {
3634    /// The name of the domain to be created.
3635    pub name: ObjectName,
3636    /// The data type of the domain.
3637    pub data_type: DataType,
3638    /// The collation of the domain.
3639    pub collation: Option<Ident>,
3640    /// The default value of the domain.
3641    pub default: Option<Expr>,
3642    /// The constraints of the domain.
3643    pub constraints: Vec<TableConstraint>,
3644}
3645
3646impl fmt::Display for CreateDomain {
3647    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3648        write!(
3649            f,
3650            "CREATE DOMAIN {name} AS {data_type}",
3651            name = self.name,
3652            data_type = self.data_type
3653        )?;
3654        if let Some(collation) = &self.collation {
3655            write!(f, " COLLATE {collation}")?;
3656        }
3657        if let Some(default) = &self.default {
3658            write!(f, " DEFAULT {default}")?;
3659        }
3660        if !self.constraints.is_empty() {
3661            write!(f, " {}", display_separated(&self.constraints, " "))?;
3662        }
3663        Ok(())
3664    }
3665}
3666
3667/// The return type of a `CREATE FUNCTION` statement.
3668#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3669#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3670#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3671pub enum FunctionReturnType {
3672    /// `RETURNS <type>`
3673    DataType(DataType),
3674    /// `RETURNS SETOF <type>`
3675    ///
3676    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3677    SetOf(DataType),
3678}
3679
3680impl fmt::Display for FunctionReturnType {
3681    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3682        match self {
3683            FunctionReturnType::DataType(data_type) => write!(f, "{data_type}"),
3684            FunctionReturnType::SetOf(data_type) => write!(f, "SETOF {data_type}"),
3685        }
3686    }
3687}
3688
3689#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3690#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3691#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3692/// CREATE FUNCTION statement
3693pub struct CreateFunction {
3694    /// True if this is a `CREATE OR ALTER FUNCTION` statement
3695    ///
3696    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql?view=sql-server-ver16#or-alter)
3697    pub or_alter: bool,
3698    /// True if this is a `CREATE OR REPLACE FUNCTION` statement
3699    pub or_replace: bool,
3700    /// True if this is a `CREATE TEMPORARY FUNCTION` statement
3701    pub temporary: bool,
3702    /// True if this is a `CREATE IF NOT EXISTS FUNCTION` statement
3703    pub if_not_exists: bool,
3704    /// Name of the function to be created.
3705    pub name: ObjectName,
3706    /// List of arguments for the function.
3707    pub args: Option<Vec<OperateFunctionArg>>,
3708    /// The return type of the function.
3709    pub return_type: Option<FunctionReturnType>,
3710    /// The expression that defines the function.
3711    ///
3712    /// Examples:
3713    /// ```sql
3714    /// AS ((SELECT 1))
3715    /// AS "console.log();"
3716    /// ```
3717    pub function_body: Option<CreateFunctionBody>,
3718    /// Behavior attribute for the function
3719    ///
3720    /// IMMUTABLE | STABLE | VOLATILE
3721    ///
3722    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3723    pub behavior: Option<FunctionBehavior>,
3724    /// CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
3725    ///
3726    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3727    pub called_on_null: Option<FunctionCalledOnNull>,
3728    /// PARALLEL { UNSAFE | RESTRICTED | SAFE }
3729    ///
3730    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3731    pub parallel: Option<FunctionParallel>,
3732    /// SECURITY { DEFINER | INVOKER }
3733    ///
3734    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3735    pub security: Option<FunctionSecurity>,
3736    /// SET configuration_parameter clauses
3737    ///
3738    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3739    pub set_params: Vec<FunctionDefinitionSetParam>,
3740    /// USING ... (Hive only)
3741    pub using: Option<CreateFunctionUsing>,
3742    /// Language used in a UDF definition.
3743    ///
3744    /// Example:
3745    /// ```sql
3746    /// CREATE FUNCTION foo() LANGUAGE js AS "console.log();"
3747    /// ```
3748    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_javascript_udf)
3749    pub language: Option<Ident>,
3750    /// Determinism keyword used for non-sql UDF definitions.
3751    ///
3752    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
3753    pub determinism_specifier: Option<FunctionDeterminismSpecifier>,
3754    /// List of options for creating the function.
3755    ///
3756    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
3757    pub options: Option<Vec<SqlOption>>,
3758    /// Connection resource for a remote function.
3759    ///
3760    /// Example:
3761    /// ```sql
3762    /// CREATE FUNCTION foo()
3763    /// RETURNS FLOAT64
3764    /// REMOTE WITH CONNECTION us.myconnection
3765    /// ```
3766    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
3767    pub remote_connection: Option<ObjectName>,
3768}
3769
3770impl fmt::Display for CreateFunction {
3771    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3772        write!(
3773            f,
3774            "CREATE {or_alter}{or_replace}{temp}FUNCTION {if_not_exists}{name}",
3775            name = self.name,
3776            temp = if self.temporary { "TEMPORARY " } else { "" },
3777            or_alter = if self.or_alter { "OR ALTER " } else { "" },
3778            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
3779            if_not_exists = if self.if_not_exists {
3780                "IF NOT EXISTS "
3781            } else {
3782                ""
3783            },
3784        )?;
3785        if let Some(args) = &self.args {
3786            write!(f, "({})", display_comma_separated(args))?;
3787        }
3788        if let Some(return_type) = &self.return_type {
3789            write!(f, " RETURNS {return_type}")?;
3790        }
3791        if let Some(determinism_specifier) = &self.determinism_specifier {
3792            write!(f, " {determinism_specifier}")?;
3793        }
3794        if let Some(language) = &self.language {
3795            write!(f, " LANGUAGE {language}")?;
3796        }
3797        if let Some(behavior) = &self.behavior {
3798            write!(f, " {behavior}")?;
3799        }
3800        if let Some(called_on_null) = &self.called_on_null {
3801            write!(f, " {called_on_null}")?;
3802        }
3803        if let Some(parallel) = &self.parallel {
3804            write!(f, " {parallel}")?;
3805        }
3806        if let Some(security) = &self.security {
3807            write!(f, " {security}")?;
3808        }
3809        for set_param in &self.set_params {
3810            write!(f, " {set_param}")?;
3811        }
3812        if let Some(remote_connection) = &self.remote_connection {
3813            write!(f, " REMOTE WITH CONNECTION {remote_connection}")?;
3814        }
3815        if let Some(CreateFunctionBody::AsBeforeOptions { body, link_symbol }) = &self.function_body
3816        {
3817            write!(f, " AS {body}")?;
3818            if let Some(link_symbol) = link_symbol {
3819                write!(f, ", {link_symbol}")?;
3820            }
3821        }
3822        if let Some(CreateFunctionBody::Return(function_body)) = &self.function_body {
3823            write!(f, " RETURN {function_body}")?;
3824        }
3825        if let Some(CreateFunctionBody::AsReturnExpr(function_body)) = &self.function_body {
3826            write!(f, " AS RETURN {function_body}")?;
3827        }
3828        if let Some(CreateFunctionBody::AsReturnSelect(function_body)) = &self.function_body {
3829            write!(f, " AS RETURN {function_body}")?;
3830        }
3831        if let Some(using) = &self.using {
3832            write!(f, " {using}")?;
3833        }
3834        if let Some(options) = &self.options {
3835            write!(
3836                f,
3837                " OPTIONS({})",
3838                display_comma_separated(options.as_slice())
3839            )?;
3840        }
3841        if let Some(CreateFunctionBody::AsAfterOptions(function_body)) = &self.function_body {
3842            write!(f, " AS {function_body}")?;
3843        }
3844        if let Some(CreateFunctionBody::AsBeginEnd(bes)) = &self.function_body {
3845            write!(f, " AS {bes}")?;
3846        }
3847        Ok(())
3848    }
3849}
3850
3851/// ```sql
3852/// CREATE CONNECTOR [IF NOT EXISTS] connector_name
3853/// [TYPE datasource_type]
3854/// [URL datasource_url]
3855/// [COMMENT connector_comment]
3856/// [WITH DCPROPERTIES(property_name=property_value, ...)]
3857/// ```
3858///
3859/// [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
3860#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3861#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3862#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3863pub struct CreateConnector {
3864    /// The name of the connector to be created.
3865    pub name: Ident,
3866    /// Whether `IF NOT EXISTS` was specified.
3867    pub if_not_exists: bool,
3868    /// The type of the connector.
3869    pub connector_type: Option<String>,
3870    /// The URL of the connector.
3871    pub url: Option<String>,
3872    /// The comment for the connector.
3873    pub comment: Option<CommentDef>,
3874    /// The DC properties for the connector.
3875    pub with_dcproperties: Option<Vec<SqlOption>>,
3876}
3877
3878impl fmt::Display for CreateConnector {
3879    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3880        write!(
3881            f,
3882            "CREATE CONNECTOR {if_not_exists}{name}",
3883            if_not_exists = if self.if_not_exists {
3884                "IF NOT EXISTS "
3885            } else {
3886                ""
3887            },
3888            name = self.name,
3889        )?;
3890
3891        if let Some(connector_type) = &self.connector_type {
3892            write!(f, " TYPE '{connector_type}'")?;
3893        }
3894
3895        if let Some(url) = &self.url {
3896            write!(f, " URL '{url}'")?;
3897        }
3898
3899        if let Some(comment) = &self.comment {
3900            write!(f, " COMMENT = '{comment}'")?;
3901        }
3902
3903        if let Some(with_dcproperties) = &self.with_dcproperties {
3904            write!(
3905                f,
3906                " WITH DCPROPERTIES({})",
3907                display_comma_separated(with_dcproperties)
3908            )?;
3909        }
3910
3911        Ok(())
3912    }
3913}
3914
3915/// An `ALTER SCHEMA` (`Statement::AlterSchema`) operation.
3916///
3917/// See [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#alter_schema_collate_statement)
3918/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterschema.html)
3919#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3920#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3921#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3922pub enum AlterSchemaOperation {
3923    /// Set the default collation for the schema.
3924    SetDefaultCollate {
3925        /// The collation to set as default.
3926        collate: Expr,
3927    },
3928    /// Add a replica to the schema.
3929    AddReplica {
3930        /// The replica to add.
3931        replica: Ident,
3932        /// Optional options for the replica.
3933        options: Option<Vec<SqlOption>>,
3934    },
3935    /// Drop a replica from the schema.
3936    DropReplica {
3937        /// The replica to drop.
3938        replica: Ident,
3939    },
3940    /// Set options for the schema.
3941    SetOptionsParens {
3942        /// The options to set.
3943        options: Vec<SqlOption>,
3944    },
3945    /// Rename the schema.
3946    Rename {
3947        /// The new name for the schema.
3948        name: ObjectName,
3949    },
3950    /// Change the owner of the schema.
3951    OwnerTo {
3952        /// The new owner of the schema.
3953        owner: Owner,
3954    },
3955}
3956
3957impl fmt::Display for AlterSchemaOperation {
3958    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3959        match self {
3960            AlterSchemaOperation::SetDefaultCollate { collate } => {
3961                write!(f, "SET DEFAULT COLLATE {collate}")
3962            }
3963            AlterSchemaOperation::AddReplica { replica, options } => {
3964                write!(f, "ADD REPLICA {replica}")?;
3965                if let Some(options) = options {
3966                    write!(f, " OPTIONS ({})", display_comma_separated(options))?;
3967                }
3968                Ok(())
3969            }
3970            AlterSchemaOperation::DropReplica { replica } => write!(f, "DROP REPLICA {replica}"),
3971            AlterSchemaOperation::SetOptionsParens { options } => {
3972                write!(f, "SET OPTIONS ({})", display_comma_separated(options))
3973            }
3974            AlterSchemaOperation::Rename { name } => write!(f, "RENAME TO {name}"),
3975            AlterSchemaOperation::OwnerTo { owner } => write!(f, "OWNER TO {owner}"),
3976        }
3977    }
3978}
3979/// `RenameTableNameKind` is the kind used in an `ALTER TABLE _ RENAME` statement.
3980///
3981/// Note: [MySQL] is the only database that supports the AS keyword for this operation.
3982///
3983/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
3984#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3985#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3986#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3987pub enum RenameTableNameKind {
3988    /// `AS new_table_name`
3989    As(ObjectName),
3990    /// `TO new_table_name`
3991    To(ObjectName),
3992}
3993
3994impl fmt::Display for RenameTableNameKind {
3995    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3996        match self {
3997            RenameTableNameKind::As(name) => write!(f, "AS {name}"),
3998            RenameTableNameKind::To(name) => write!(f, "TO {name}"),
3999        }
4000    }
4001}
4002
4003#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4004#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4005#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4006/// An `ALTER SCHEMA` (`Statement::AlterSchema`) statement.
4007pub struct AlterSchema {
4008    /// The schema name to alter.
4009    pub name: ObjectName,
4010    /// Whether `IF EXISTS` was specified.
4011    pub if_exists: bool,
4012    /// The list of operations to perform on the schema.
4013    pub operations: Vec<AlterSchemaOperation>,
4014}
4015
4016impl fmt::Display for AlterSchema {
4017    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4018        write!(f, "ALTER SCHEMA ")?;
4019        if self.if_exists {
4020            write!(f, "IF EXISTS ")?;
4021        }
4022        write!(f, "{}", self.name)?;
4023        for operation in &self.operations {
4024            write!(f, " {operation}")?;
4025        }
4026
4027        Ok(())
4028    }
4029}
4030
4031impl Spanned for RenameTableNameKind {
4032    fn span(&self) -> Span {
4033        match self {
4034            RenameTableNameKind::As(name) => name.span(),
4035            RenameTableNameKind::To(name) => name.span(),
4036        }
4037    }
4038}
4039
4040#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
4041#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4042#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4043/// Whether the syntax used for the trigger object (ROW or STATEMENT) is `FOR` or `FOR EACH`.
4044pub enum TriggerObjectKind {
4045    /// The `FOR` syntax is used.
4046    For(TriggerObject),
4047    /// The `FOR EACH` syntax is used.
4048    ForEach(TriggerObject),
4049}
4050
4051impl Display for TriggerObjectKind {
4052    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4053        match self {
4054            TriggerObjectKind::For(obj) => write!(f, "FOR {obj}"),
4055            TriggerObjectKind::ForEach(obj) => write!(f, "FOR EACH {obj}"),
4056        }
4057    }
4058}
4059
4060#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4061#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4062#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4063/// CREATE TRIGGER
4064///
4065/// Examples:
4066///
4067/// ```sql
4068/// CREATE TRIGGER trigger_name
4069/// BEFORE INSERT ON table_name
4070/// FOR EACH ROW
4071/// EXECUTE FUNCTION trigger_function();
4072/// ```
4073///
4074/// Postgres: <https://www.postgresql.org/docs/current/sql-createtrigger.html>
4075/// SQL Server: <https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql>
4076pub struct CreateTrigger {
4077    /// True if this is a `CREATE OR ALTER TRIGGER` statement
4078    ///
4079    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql?view=sql-server-ver16#arguments)
4080    pub or_alter: bool,
4081    /// True if this is a temporary trigger.
4082    ///
4083    /// Examples:
4084    ///
4085    /// ```sql
4086    /// CREATE TEMP TRIGGER trigger_name
4087    /// ```
4088    ///
4089    /// or
4090    ///
4091    /// ```sql
4092    /// CREATE TEMPORARY TRIGGER trigger_name;
4093    /// CREATE TEMP TRIGGER trigger_name;
4094    /// ```
4095    ///
4096    /// [SQLite](https://sqlite.org/lang_createtrigger.html#temp_triggers_on_non_temp_tables)
4097    pub temporary: bool,
4098    /// The `OR REPLACE` clause is used to re-create the trigger if it already exists.
4099    ///
4100    /// Example:
4101    /// ```sql
4102    /// CREATE OR REPLACE TRIGGER trigger_name
4103    /// AFTER INSERT ON table_name
4104    /// FOR EACH ROW
4105    /// EXECUTE FUNCTION trigger_function();
4106    /// ```
4107    pub or_replace: bool,
4108    /// The `CONSTRAINT` keyword is used to create a trigger as a constraint.
4109    pub is_constraint: bool,
4110    /// The name of the trigger to be created.
4111    pub name: ObjectName,
4112    /// Determines whether the function is called before, after, or instead of the event.
4113    ///
4114    /// Example of BEFORE:
4115    ///
4116    /// ```sql
4117    /// CREATE TRIGGER trigger_name
4118    /// BEFORE INSERT ON table_name
4119    /// FOR EACH ROW
4120    /// EXECUTE FUNCTION trigger_function();
4121    /// ```
4122    ///
4123    /// Example of AFTER:
4124    ///
4125    /// ```sql
4126    /// CREATE TRIGGER trigger_name
4127    /// AFTER INSERT ON table_name
4128    /// FOR EACH ROW
4129    /// EXECUTE FUNCTION trigger_function();
4130    /// ```
4131    ///
4132    /// Example of INSTEAD OF:
4133    ///
4134    /// ```sql
4135    /// CREATE TRIGGER trigger_name
4136    /// INSTEAD OF INSERT ON table_name
4137    /// FOR EACH ROW
4138    /// EXECUTE FUNCTION trigger_function();
4139    /// ```
4140    pub period: Option<TriggerPeriod>,
4141    /// Whether the trigger period was specified before the target table name.
4142    /// This does not refer to whether the period is BEFORE, AFTER, or INSTEAD OF,
4143    /// but rather the position of the period clause in relation to the table name.
4144    ///
4145    /// ```sql
4146    /// -- period_before_table == true: Postgres, MySQL, and standard SQL
4147    /// CREATE TRIGGER t BEFORE INSERT ON table_name ...;
4148    /// -- period_before_table == false: MSSQL
4149    /// CREATE TRIGGER t ON table_name BEFORE INSERT ...;
4150    /// ```
4151    pub period_before_table: bool,
4152    /// Multiple events can be specified using OR, such as `INSERT`, `UPDATE`, `DELETE`, or `TRUNCATE`.
4153    pub events: Vec<TriggerEvent>,
4154    /// The table on which the trigger is to be created.
4155    pub table_name: ObjectName,
4156    /// The optional referenced table name that can be referenced via
4157    /// the `FROM` keyword.
4158    pub referenced_table_name: Option<ObjectName>,
4159    /// This keyword immediately precedes the declaration of one or two relation names that provide access to the transition relations of the triggering statement.
4160    pub referencing: Vec<TriggerReferencing>,
4161    /// This specifies whether the trigger function should be fired once for
4162    /// every row affected by the trigger event, or just once per SQL statement.
4163    /// This is optional in some SQL dialects, such as SQLite, and if not specified, in
4164    /// those cases, the implied default is `FOR EACH ROW`.
4165    pub trigger_object: Option<TriggerObjectKind>,
4166    ///  Triggering conditions
4167    pub condition: Option<Expr>,
4168    /// Execute logic block
4169    pub exec_body: Option<TriggerExecBody>,
4170    /// For MSSQL and dialects where statements are preceded by `AS`
4171    pub statements_as: bool,
4172    /// For SQL dialects with statement(s) for a body
4173    pub statements: Option<ConditionalStatements>,
4174    /// The characteristic of the trigger, which include whether the trigger is `DEFERRABLE`, `INITIALLY DEFERRED`, or `INITIALLY IMMEDIATE`,
4175    pub characteristics: Option<ConstraintCharacteristics>,
4176}
4177
4178impl Display for CreateTrigger {
4179    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4180        let CreateTrigger {
4181            or_alter,
4182            temporary,
4183            or_replace,
4184            is_constraint,
4185            name,
4186            period_before_table,
4187            period,
4188            events,
4189            table_name,
4190            referenced_table_name,
4191            referencing,
4192            trigger_object,
4193            condition,
4194            exec_body,
4195            statements_as,
4196            statements,
4197            characteristics,
4198        } = self;
4199        write!(
4200            f,
4201            "CREATE {temporary}{or_alter}{or_replace}{is_constraint}TRIGGER {name} ",
4202            temporary = if *temporary { "TEMPORARY " } else { "" },
4203            or_alter = if *or_alter { "OR ALTER " } else { "" },
4204            or_replace = if *or_replace { "OR REPLACE " } else { "" },
4205            is_constraint = if *is_constraint { "CONSTRAINT " } else { "" },
4206        )?;
4207
4208        if *period_before_table {
4209            if let Some(p) = period {
4210                write!(f, "{p} ")?;
4211            }
4212            if !events.is_empty() {
4213                write!(f, "{} ", display_separated(events, " OR "))?;
4214            }
4215            write!(f, "ON {table_name}")?;
4216        } else {
4217            write!(f, "ON {table_name} ")?;
4218            if let Some(p) = period {
4219                write!(f, "{p}")?;
4220            }
4221            if !events.is_empty() {
4222                write!(f, " {}", display_separated(events, ", "))?;
4223            }
4224        }
4225
4226        if let Some(referenced_table_name) = referenced_table_name {
4227            write!(f, " FROM {referenced_table_name}")?;
4228        }
4229
4230        if let Some(characteristics) = characteristics {
4231            write!(f, " {characteristics}")?;
4232        }
4233
4234        if !referencing.is_empty() {
4235            write!(f, " REFERENCING {}", display_separated(referencing, " "))?;
4236        }
4237
4238        if let Some(trigger_object) = trigger_object {
4239            write!(f, " {trigger_object}")?;
4240        }
4241        if let Some(condition) = condition {
4242            write!(f, " WHEN {condition}")?;
4243        }
4244        if let Some(exec_body) = exec_body {
4245            write!(f, " EXECUTE {exec_body}")?;
4246        }
4247        if let Some(statements) = statements {
4248            if *statements_as {
4249                write!(f, " AS")?;
4250            }
4251            write!(f, " {statements}")?;
4252        }
4253        Ok(())
4254    }
4255}
4256
4257#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4258#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4259#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4260/// DROP TRIGGER
4261///
4262/// ```sql
4263/// DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
4264/// ```
4265///
4266pub struct DropTrigger {
4267    /// Whether to include the `IF EXISTS` clause.
4268    pub if_exists: bool,
4269    /// The name of the trigger to be dropped.
4270    pub trigger_name: ObjectName,
4271    /// The name of the table from which the trigger is to be dropped.
4272    pub table_name: Option<ObjectName>,
4273    /// `CASCADE` or `RESTRICT`
4274    pub option: Option<ReferentialAction>,
4275}
4276
4277impl fmt::Display for DropTrigger {
4278    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4279        let DropTrigger {
4280            if_exists,
4281            trigger_name,
4282            table_name,
4283            option,
4284        } = self;
4285        write!(f, "DROP TRIGGER")?;
4286        if *if_exists {
4287            write!(f, " IF EXISTS")?;
4288        }
4289        match &table_name {
4290            Some(table_name) => write!(f, " {trigger_name} ON {table_name}")?,
4291            None => write!(f, " {trigger_name}")?,
4292        };
4293        if let Some(option) = option {
4294            write!(f, " {option}")?;
4295        }
4296        Ok(())
4297    }
4298}
4299
4300/// A `TRUNCATE` statement.
4301///
4302/// ```sql
4303/// TRUNCATE TABLE [IF EXISTS] table_names [PARTITION (partitions)] [RESTART IDENTITY | CONTINUE IDENTITY] [CASCADE | RESTRICT] [ON CLUSTER cluster_name]
4304/// ```
4305#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4306#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4307#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4308pub struct Truncate {
4309    /// Table names to truncate
4310    pub table_names: Vec<super::TruncateTableTarget>,
4311    /// Optional partition specification
4312    pub partitions: Option<Vec<Expr>>,
4313    /// TABLE - optional keyword
4314    pub table: bool,
4315    /// Snowflake/Redshift-specific option: [ IF EXISTS ]
4316    pub if_exists: bool,
4317    /// Postgres-specific option: [ RESTART IDENTITY | CONTINUE IDENTITY ]
4318    pub identity: Option<super::TruncateIdentityOption>,
4319    /// Postgres-specific option: [ CASCADE | RESTRICT ]
4320    pub cascade: Option<super::CascadeOption>,
4321    /// ClickHouse-specific option: [ ON CLUSTER cluster_name ]
4322    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/truncate/)
4323    pub on_cluster: Option<Ident>,
4324}
4325
4326impl fmt::Display for Truncate {
4327    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4328        let table = if self.table { "TABLE " } else { "" };
4329        let if_exists = if self.if_exists { "IF EXISTS " } else { "" };
4330
4331        write!(
4332            f,
4333            "TRUNCATE {table}{if_exists}{table_names}",
4334            table_names = display_comma_separated(&self.table_names)
4335        )?;
4336
4337        if let Some(identity) = &self.identity {
4338            match identity {
4339                super::TruncateIdentityOption::Restart => write!(f, " RESTART IDENTITY")?,
4340                super::TruncateIdentityOption::Continue => write!(f, " CONTINUE IDENTITY")?,
4341            }
4342        }
4343        if let Some(cascade) = &self.cascade {
4344            match cascade {
4345                super::CascadeOption::Cascade => write!(f, " CASCADE")?,
4346                super::CascadeOption::Restrict => write!(f, " RESTRICT")?,
4347            }
4348        }
4349
4350        if let Some(ref parts) = &self.partitions {
4351            if !parts.is_empty() {
4352                write!(f, " PARTITION ({})", display_comma_separated(parts))?;
4353            }
4354        }
4355        if let Some(on_cluster) = &self.on_cluster {
4356            write!(f, " ON CLUSTER {on_cluster}")?;
4357        }
4358        Ok(())
4359    }
4360}
4361
4362impl Spanned for Truncate {
4363    fn span(&self) -> Span {
4364        Span::union_iter(
4365            self.table_names.iter().map(|i| i.name.span()).chain(
4366                self.partitions
4367                    .iter()
4368                    .flat_map(|i| i.iter().map(|k| k.span())),
4369            ),
4370        )
4371    }
4372}
4373
4374/// An `MSCK` statement.
4375///
4376/// ```sql
4377/// MSCK [REPAIR] TABLE table_name [ADD|DROP|SYNC PARTITIONS]
4378/// ```
4379/// MSCK (Hive) - MetaStore Check command
4380#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4381#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4382#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4383pub struct Msck {
4384    /// Table name to check
4385    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
4386    pub table_name: ObjectName,
4387    /// Whether to repair the table
4388    pub repair: bool,
4389    /// Partition action (ADD, DROP, or SYNC)
4390    pub partition_action: Option<super::AddDropSync>,
4391}
4392
4393impl fmt::Display for Msck {
4394    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4395        write!(
4396            f,
4397            "MSCK {repair}TABLE {table}",
4398            repair = if self.repair { "REPAIR " } else { "" },
4399            table = self.table_name
4400        )?;
4401        if let Some(pa) = &self.partition_action {
4402            write!(f, " {pa}")?;
4403        }
4404        Ok(())
4405    }
4406}
4407
4408impl Spanned for Msck {
4409    fn span(&self) -> Span {
4410        self.table_name.span()
4411    }
4412}
4413
4414/// CREATE VIEW statement.
4415#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4416#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4417#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4418pub struct CreateView {
4419    /// True if this is a `CREATE OR ALTER VIEW` statement
4420    ///
4421    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-view-transact-sql)
4422    pub or_alter: bool,
4423    /// The `OR REPLACE` clause is used to re-create the view if it already exists.
4424    pub or_replace: bool,
4425    /// if true, has MATERIALIZED view modifier
4426    pub materialized: bool,
4427    /// Snowflake: SECURE view modifier
4428    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
4429    pub secure: bool,
4430    /// View name
4431    pub name: ObjectName,
4432    /// If `if_not_exists` is true, this flag is set to true if the view name comes before the `IF NOT EXISTS` clause.
4433    /// Example:
4434    /// ```sql
4435    /// CREATE VIEW myview IF NOT EXISTS AS SELECT 1`
4436    ///  ```
4437    /// Otherwise, the flag is set to false if the view name comes after the clause
4438    /// Example:
4439    /// ```sql
4440    /// CREATE VIEW IF NOT EXISTS myview AS SELECT 1`
4441    ///  ```
4442    pub name_before_not_exists: bool,
4443    /// Optional column definitions
4444    pub columns: Vec<ViewColumnDef>,
4445    /// The query that defines the view.
4446    pub query: Box<Query>,
4447    /// Table options (e.g., WITH (..), OPTIONS (...))
4448    pub options: CreateTableOptions,
4449    /// BigQuery: CLUSTER BY columns
4450    pub cluster_by: Vec<Ident>,
4451    /// Snowflake: Views can have comments in Snowflake.
4452    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
4453    pub comment: Option<String>,
4454    /// if true, has RedShift [`WITH NO SCHEMA BINDING`] clause <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_VIEW.html>
4455    pub with_no_schema_binding: bool,
4456    /// if true, has SQLite `IF NOT EXISTS` clause <https://www.sqlite.org/lang_createview.html>
4457    pub if_not_exists: bool,
4458    /// if true, has SQLite `TEMP` or `TEMPORARY` clause <https://www.sqlite.org/lang_createview.html>
4459    pub temporary: bool,
4460    /// Snowflake: `COPY GRANTS` clause
4461    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view>
4462    pub copy_grants: bool,
4463    /// if not None, has Clickhouse `TO` clause, specify the table into which to insert results
4464    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/view#materialized-view>
4465    pub to: Option<ObjectName>,
4466    /// MySQL: Optional parameters for the view algorithm, definer, and security context
4467    pub params: Option<CreateViewParams>,
4468}
4469
4470impl fmt::Display for CreateView {
4471    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4472        write!(
4473            f,
4474            "CREATE {or_alter}{or_replace}",
4475            or_alter = if self.or_alter { "OR ALTER " } else { "" },
4476            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
4477        )?;
4478        if let Some(ref params) = self.params {
4479            params.fmt(f)?;
4480        }
4481        write!(
4482            f,
4483            "{secure}{materialized}{temporary}VIEW {if_not_and_name}{to}",
4484            if_not_and_name = if self.if_not_exists {
4485                if self.name_before_not_exists {
4486                    format!("{} IF NOT EXISTS", self.name)
4487                } else {
4488                    format!("IF NOT EXISTS {}", self.name)
4489                }
4490            } else {
4491                format!("{}", self.name)
4492            },
4493            secure = if self.secure { "SECURE " } else { "" },
4494            materialized = if self.materialized {
4495                "MATERIALIZED "
4496            } else {
4497                ""
4498            },
4499            temporary = if self.temporary { "TEMPORARY " } else { "" },
4500            to = self
4501                .to
4502                .as_ref()
4503                .map(|to| format!(" TO {to}"))
4504                .unwrap_or_default()
4505        )?;
4506        if self.copy_grants {
4507            write!(f, " COPY GRANTS")?;
4508        }
4509        if !self.columns.is_empty() {
4510            write!(f, " ({})", display_comma_separated(&self.columns))?;
4511        }
4512        if matches!(self.options, CreateTableOptions::With(_)) {
4513            write!(f, " {}", self.options)?;
4514        }
4515        if let Some(ref comment) = self.comment {
4516            write!(f, " COMMENT = '{}'", escape_single_quote_string(comment))?;
4517        }
4518        if !self.cluster_by.is_empty() {
4519            write!(
4520                f,
4521                " CLUSTER BY ({})",
4522                display_comma_separated(&self.cluster_by)
4523            )?;
4524        }
4525        if matches!(self.options, CreateTableOptions::Options(_)) {
4526            write!(f, " {}", self.options)?;
4527        }
4528        f.write_str(" AS")?;
4529        SpaceOrNewline.fmt(f)?;
4530        self.query.fmt(f)?;
4531        if self.with_no_schema_binding {
4532            write!(f, " WITH NO SCHEMA BINDING")?;
4533        }
4534        Ok(())
4535    }
4536}
4537
4538/// CREATE EXTENSION statement
4539/// Note: this is a PostgreSQL-specific statement
4540#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4541#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4542#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4543pub struct CreateExtension {
4544    /// Extension name
4545    pub name: Ident,
4546    /// Whether `IF NOT EXISTS` was specified for the CREATE EXTENSION.
4547    pub if_not_exists: bool,
4548    /// Whether `CASCADE` was specified for the CREATE EXTENSION.
4549    pub cascade: bool,
4550    /// Optional schema name for the extension.
4551    pub schema: Option<Ident>,
4552    /// Optional version for the extension.
4553    pub version: Option<Ident>,
4554}
4555
4556impl fmt::Display for CreateExtension {
4557    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4558        write!(
4559            f,
4560            "CREATE EXTENSION {if_not_exists}{name}",
4561            if_not_exists = if self.if_not_exists {
4562                "IF NOT EXISTS "
4563            } else {
4564                ""
4565            },
4566            name = self.name
4567        )?;
4568        if self.cascade || self.schema.is_some() || self.version.is_some() {
4569            write!(f, " WITH")?;
4570
4571            if let Some(name) = &self.schema {
4572                write!(f, " SCHEMA {name}")?;
4573            }
4574            if let Some(version) = &self.version {
4575                write!(f, " VERSION {version}")?;
4576            }
4577            if self.cascade {
4578                write!(f, " CASCADE")?;
4579            }
4580        }
4581
4582        Ok(())
4583    }
4584}
4585
4586impl Spanned for CreateExtension {
4587    fn span(&self) -> Span {
4588        Span::empty()
4589    }
4590}
4591
4592/// DROP EXTENSION statement
4593/// Note: this is a PostgreSQL-specific statement
4594///
4595/// # References
4596///
4597/// PostgreSQL Documentation:
4598/// <https://www.postgresql.org/docs/current/sql-dropextension.html>
4599#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4600#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4601#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4602pub struct DropExtension {
4603    /// One or more extension names to drop
4604    pub names: Vec<Ident>,
4605    /// Whether `IF EXISTS` was specified for the DROP EXTENSION.
4606    pub if_exists: bool,
4607    /// `CASCADE` or `RESTRICT` behaviour for the drop.
4608    pub cascade_or_restrict: Option<ReferentialAction>,
4609}
4610
4611impl fmt::Display for DropExtension {
4612    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4613        write!(f, "DROP EXTENSION")?;
4614        if self.if_exists {
4615            write!(f, " IF EXISTS")?;
4616        }
4617        write!(f, " {}", display_comma_separated(&self.names))?;
4618        if let Some(cascade_or_restrict) = &self.cascade_or_restrict {
4619            write!(f, " {cascade_or_restrict}")?;
4620        }
4621        Ok(())
4622    }
4623}
4624
4625impl Spanned for DropExtension {
4626    fn span(&self) -> Span {
4627        Span::empty()
4628    }
4629}
4630
4631/// CREATE COLLATION statement.
4632/// Note: this is a PostgreSQL-specific statement.
4633#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4634#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4635#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4636pub struct CreateCollation {
4637    /// Whether `IF NOT EXISTS` was specified.
4638    pub if_not_exists: bool,
4639    /// Name of the collation being created.
4640    pub name: ObjectName,
4641    /// Source definition for the collation.
4642    pub definition: CreateCollationDefinition,
4643}
4644
4645/// Definition forms supported by `CREATE COLLATION`.
4646#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4647#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4648#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4649pub enum CreateCollationDefinition {
4650    /// Create from an existing collation.
4651    ///
4652    /// ```sql
4653    /// CREATE COLLATION name FROM existing_collation
4654    /// ```
4655    From(ObjectName),
4656    /// Create with an option list.
4657    ///
4658    /// ```sql
4659    /// CREATE COLLATION name (key = value, ...)
4660    /// ```
4661    Options(Vec<SqlOption>),
4662}
4663
4664impl fmt::Display for CreateCollation {
4665    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4666        write!(
4667            f,
4668            "CREATE COLLATION {if_not_exists}{name}",
4669            if_not_exists = if self.if_not_exists {
4670                "IF NOT EXISTS "
4671            } else {
4672                ""
4673            },
4674            name = self.name
4675        )?;
4676        match &self.definition {
4677            CreateCollationDefinition::From(existing_collation) => {
4678                write!(f, " FROM {existing_collation}")
4679            }
4680            CreateCollationDefinition::Options(options) => {
4681                write!(f, " ({})", display_comma_separated(options))
4682            }
4683        }
4684    }
4685}
4686
4687impl Spanned for CreateCollation {
4688    fn span(&self) -> Span {
4689        Span::empty()
4690    }
4691}
4692
4693/// ALTER COLLATION statement.
4694/// Note: this is a PostgreSQL-specific statement.
4695#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4696#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4697#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4698pub struct AlterCollation {
4699    /// Name of the collation being altered.
4700    pub name: ObjectName,
4701    /// The operation to perform on the collation.
4702    pub operation: AlterCollationOperation,
4703}
4704
4705/// Operations supported by `ALTER COLLATION`.
4706#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4707#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4708#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4709pub enum AlterCollationOperation {
4710    /// Rename the collation.
4711    ///
4712    /// ```sql
4713    /// ALTER COLLATION name RENAME TO new_name
4714    /// ```
4715    RenameTo {
4716        /// New collation name.
4717        new_name: Ident,
4718    },
4719    /// Change the collation owner.
4720    ///
4721    /// ```sql
4722    /// ALTER COLLATION name OWNER TO role_name
4723    /// ```
4724    OwnerTo(Owner),
4725    /// Move the collation to another schema.
4726    ///
4727    /// ```sql
4728    /// ALTER COLLATION name SET SCHEMA new_schema
4729    /// ```
4730    SetSchema {
4731        /// Target schema name.
4732        schema_name: ObjectName,
4733    },
4734    /// Refresh collation version metadata.
4735    ///
4736    /// ```sql
4737    /// ALTER COLLATION name REFRESH VERSION
4738    /// ```
4739    RefreshVersion,
4740}
4741
4742impl fmt::Display for AlterCollationOperation {
4743    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4744        match self {
4745            AlterCollationOperation::RenameTo { new_name } => write!(f, "RENAME TO {new_name}"),
4746            AlterCollationOperation::OwnerTo(owner) => write!(f, "OWNER TO {owner}"),
4747            AlterCollationOperation::SetSchema { schema_name } => {
4748                write!(f, "SET SCHEMA {schema_name}")
4749            }
4750            AlterCollationOperation::RefreshVersion => write!(f, "REFRESH VERSION"),
4751        }
4752    }
4753}
4754
4755impl fmt::Display for AlterCollation {
4756    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4757        write!(f, "ALTER COLLATION {} {}", self.name, self.operation)
4758    }
4759}
4760
4761impl Spanned for AlterCollation {
4762    fn span(&self) -> Span {
4763        Span::empty()
4764    }
4765}
4766
4767/// Table type for ALTER TABLE statements.
4768/// Used to distinguish between regular tables, Iceberg tables, and Dynamic tables.
4769#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4770#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4771#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4772pub enum AlterTableType {
4773    /// Iceberg table type
4774    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
4775    Iceberg,
4776    /// Dynamic table type
4777    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-dynamic-table>
4778    Dynamic,
4779    /// External table type
4780    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
4781    External,
4782}
4783
4784/// ALTER TABLE statement
4785#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4786#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4787#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4788pub struct AlterTable {
4789    /// Table name
4790    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
4791    pub name: ObjectName,
4792    /// Whether `IF EXISTS` was specified for the `ALTER TABLE`.
4793    pub if_exists: bool,
4794    /// Whether the `ONLY` keyword was used (restrict scope to the named table).
4795    pub only: bool,
4796    /// List of `ALTER TABLE` operations to apply.
4797    pub operations: Vec<AlterTableOperation>,
4798    /// Optional Hive `SET LOCATION` clause for the alter operation.
4799    pub location: Option<HiveSetLocation>,
4800    /// ClickHouse dialect supports `ON CLUSTER` clause for ALTER TABLE
4801    /// For example: `ALTER TABLE table_name ON CLUSTER cluster_name ADD COLUMN c UInt32`
4802    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/update)
4803    pub on_cluster: Option<Ident>,
4804    /// Table type: None for regular tables, Some(AlterTableType) for Iceberg or Dynamic tables
4805    pub table_type: Option<AlterTableType>,
4806    /// Token that represents the end of the statement (semicolon or EOF)
4807    pub end_token: AttachedToken,
4808}
4809
4810impl fmt::Display for AlterTable {
4811    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4812        match &self.table_type {
4813            Some(AlterTableType::Iceberg) => write!(f, "ALTER ICEBERG TABLE ")?,
4814            Some(AlterTableType::Dynamic) => write!(f, "ALTER DYNAMIC TABLE ")?,
4815            Some(AlterTableType::External) => write!(f, "ALTER EXTERNAL TABLE ")?,
4816            None => write!(f, "ALTER TABLE ")?,
4817        }
4818
4819        if self.if_exists {
4820            write!(f, "IF EXISTS ")?;
4821        }
4822        if self.only {
4823            write!(f, "ONLY ")?;
4824        }
4825        write!(f, "{} ", &self.name)?;
4826        if let Some(cluster) = &self.on_cluster {
4827            write!(f, "ON CLUSTER {cluster} ")?;
4828        }
4829        write!(f, "{}", display_comma_separated(&self.operations))?;
4830        if let Some(loc) = &self.location {
4831            write!(f, " {loc}")?
4832        }
4833        Ok(())
4834    }
4835}
4836
4837/// DROP FUNCTION statement
4838#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4839#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4840#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4841pub struct DropFunction {
4842    /// Whether to include the `IF EXISTS` clause.
4843    pub if_exists: bool,
4844    /// One or more functions to drop
4845    pub func_desc: Vec<FunctionDesc>,
4846    /// `CASCADE` or `RESTRICT`
4847    pub drop_behavior: Option<DropBehavior>,
4848}
4849
4850impl fmt::Display for DropFunction {
4851    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4852        write!(
4853            f,
4854            "DROP FUNCTION{} {}",
4855            if self.if_exists { " IF EXISTS" } else { "" },
4856            display_comma_separated(&self.func_desc),
4857        )?;
4858        if let Some(op) = &self.drop_behavior {
4859            write!(f, " {op}")?;
4860        }
4861        Ok(())
4862    }
4863}
4864
4865impl Spanned for DropFunction {
4866    fn span(&self) -> Span {
4867        Span::empty()
4868    }
4869}
4870
4871/// CREATE OPERATOR statement
4872/// See <https://www.postgresql.org/docs/current/sql-createoperator.html>
4873#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4874#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4875#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4876pub struct CreateOperator {
4877    /// Operator name (can be schema-qualified)
4878    pub name: ObjectName,
4879    /// FUNCTION or PROCEDURE parameter (function name)
4880    pub function: ObjectName,
4881    /// Whether PROCEDURE keyword was used (vs FUNCTION)
4882    pub is_procedure: bool,
4883    /// LEFTARG parameter (left operand type)
4884    pub left_arg: Option<DataType>,
4885    /// RIGHTARG parameter (right operand type)
4886    pub right_arg: Option<DataType>,
4887    /// Operator options (COMMUTATOR, NEGATOR, RESTRICT, JOIN, HASHES, MERGES)
4888    pub options: Vec<OperatorOption>,
4889}
4890
4891/// CREATE OPERATOR FAMILY statement
4892/// See <https://www.postgresql.org/docs/current/sql-createopfamily.html>
4893#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4894#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4895#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4896pub struct CreateOperatorFamily {
4897    /// Operator family name (can be schema-qualified)
4898    pub name: ObjectName,
4899    /// Index method (btree, hash, gist, gin, etc.)
4900    pub using: Ident,
4901}
4902
4903/// CREATE OPERATOR CLASS statement
4904/// See <https://www.postgresql.org/docs/current/sql-createopclass.html>
4905#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4906#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4907#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4908pub struct CreateOperatorClass {
4909    /// Operator class name (can be schema-qualified)
4910    pub name: ObjectName,
4911    /// Whether this is the default operator class for the type
4912    pub default: bool,
4913    /// The data type
4914    pub for_type: DataType,
4915    /// Index method (btree, hash, gist, gin, etc.)
4916    pub using: Ident,
4917    /// Optional operator family name
4918    pub family: Option<ObjectName>,
4919    /// List of operator class items (operators, functions, storage)
4920    pub items: Vec<OperatorClassItem>,
4921}
4922
4923impl fmt::Display for CreateOperator {
4924    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4925        write!(f, "CREATE OPERATOR {} (", self.name)?;
4926
4927        let function_keyword = if self.is_procedure {
4928            "PROCEDURE"
4929        } else {
4930            "FUNCTION"
4931        };
4932        let mut params = vec![format!("{} = {}", function_keyword, self.function)];
4933
4934        if let Some(left_arg) = &self.left_arg {
4935            params.push(format!("LEFTARG = {}", left_arg));
4936        }
4937        if let Some(right_arg) = &self.right_arg {
4938            params.push(format!("RIGHTARG = {}", right_arg));
4939        }
4940
4941        for option in &self.options {
4942            params.push(option.to_string());
4943        }
4944
4945        write!(f, "{}", params.join(", "))?;
4946        write!(f, ")")
4947    }
4948}
4949
4950impl fmt::Display for CreateOperatorFamily {
4951    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4952        write!(
4953            f,
4954            "CREATE OPERATOR FAMILY {} USING {}",
4955            self.name, self.using
4956        )
4957    }
4958}
4959
4960impl fmt::Display for CreateOperatorClass {
4961    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4962        write!(f, "CREATE OPERATOR CLASS {}", self.name)?;
4963        if self.default {
4964            write!(f, " DEFAULT")?;
4965        }
4966        write!(f, " FOR TYPE {} USING {}", self.for_type, self.using)?;
4967        if let Some(family) = &self.family {
4968            write!(f, " FAMILY {}", family)?;
4969        }
4970        write!(f, " AS {}", display_comma_separated(&self.items))
4971    }
4972}
4973
4974/// Operator argument types for CREATE OPERATOR CLASS
4975#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4976#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4977#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4978pub struct OperatorArgTypes {
4979    /// Left-hand operand data type for the operator.
4980    pub left: DataType,
4981    /// Right-hand operand data type for the operator.
4982    pub right: DataType,
4983}
4984
4985impl fmt::Display for OperatorArgTypes {
4986    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4987        write!(f, "{}, {}", self.left, self.right)
4988    }
4989}
4990
4991/// An item in a CREATE OPERATOR CLASS statement
4992#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4993#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4994#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4995pub enum OperatorClassItem {
4996    /// `OPERATOR` clause describing a specific operator implementation.
4997    Operator {
4998        /// Strategy number identifying the operator position in the opclass.
4999        strategy_number: u64,
5000        /// The operator name referenced by this clause.
5001        operator_name: ObjectName,
5002        /// Optional operator argument types.
5003        op_types: Option<OperatorArgTypes>,
5004        /// Optional purpose such as `FOR SEARCH` or `FOR ORDER BY`.
5005        purpose: Option<OperatorPurpose>,
5006    },
5007    /// `FUNCTION` clause describing a support function for the operator class.
5008    Function {
5009        /// Support function number for this entry.
5010        support_number: u64,
5011        /// Optional function argument types for the operator class.
5012        op_types: Option<Vec<DataType>>,
5013        /// The function name implementing the support function.
5014        function_name: ObjectName,
5015        /// Function argument types for the support function.
5016        argument_types: Vec<DataType>,
5017    },
5018    /// `STORAGE` clause specifying the storage type.
5019    Storage {
5020        /// The storage data type.
5021        storage_type: DataType,
5022    },
5023}
5024
5025/// Purpose of an operator in an operator class
5026#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5027#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5028#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5029pub enum OperatorPurpose {
5030    /// Purpose: used for index/search operations.
5031    ForSearch,
5032    /// Purpose: used for ORDER BY; optionally includes a sort family name.
5033    ForOrderBy {
5034        /// Optional sort family object name.
5035        sort_family: ObjectName,
5036    },
5037}
5038
5039impl fmt::Display for OperatorClassItem {
5040    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5041        match self {
5042            OperatorClassItem::Operator {
5043                strategy_number,
5044                operator_name,
5045                op_types,
5046                purpose,
5047            } => {
5048                write!(f, "OPERATOR {strategy_number} {operator_name}")?;
5049                if let Some(types) = op_types {
5050                    write!(f, " ({types})")?;
5051                }
5052                if let Some(purpose) = purpose {
5053                    write!(f, " {purpose}")?;
5054                }
5055                Ok(())
5056            }
5057            OperatorClassItem::Function {
5058                support_number,
5059                op_types,
5060                function_name,
5061                argument_types,
5062            } => {
5063                write!(f, "FUNCTION {support_number}")?;
5064                if let Some(types) = op_types {
5065                    write!(f, " ({})", display_comma_separated(types))?;
5066                }
5067                write!(f, " {function_name}")?;
5068                if !argument_types.is_empty() {
5069                    write!(f, "({})", display_comma_separated(argument_types))?;
5070                }
5071                Ok(())
5072            }
5073            OperatorClassItem::Storage { storage_type } => {
5074                write!(f, "STORAGE {storage_type}")
5075            }
5076        }
5077    }
5078}
5079
5080impl fmt::Display for OperatorPurpose {
5081    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5082        match self {
5083            OperatorPurpose::ForSearch => write!(f, "FOR SEARCH"),
5084            OperatorPurpose::ForOrderBy { sort_family } => {
5085                write!(f, "FOR ORDER BY {sort_family}")
5086            }
5087        }
5088    }
5089}
5090
5091/// `DROP OPERATOR` statement
5092/// See <https://www.postgresql.org/docs/current/sql-dropoperator.html>
5093#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5094#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5095#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5096pub struct DropOperator {
5097    /// `IF EXISTS` clause
5098    pub if_exists: bool,
5099    /// One or more operators to drop with their signatures
5100    pub operators: Vec<DropOperatorSignature>,
5101    /// `CASCADE or RESTRICT`
5102    pub drop_behavior: Option<DropBehavior>,
5103}
5104
5105/// Operator signature for a `DROP OPERATOR` statement
5106#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5107#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5108#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5109pub struct DropOperatorSignature {
5110    /// Operator name
5111    pub name: ObjectName,
5112    /// Left operand type
5113    pub left_type: Option<DataType>,
5114    /// Right operand type
5115    pub right_type: DataType,
5116}
5117
5118impl fmt::Display for DropOperatorSignature {
5119    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5120        write!(f, "{} (", self.name)?;
5121        if let Some(left_type) = &self.left_type {
5122            write!(f, "{}", left_type)?;
5123        } else {
5124            write!(f, "NONE")?;
5125        }
5126        write!(f, ", {})", self.right_type)
5127    }
5128}
5129
5130impl fmt::Display for DropOperator {
5131    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5132        write!(f, "DROP OPERATOR")?;
5133        if self.if_exists {
5134            write!(f, " IF EXISTS")?;
5135        }
5136        write!(f, " {}", display_comma_separated(&self.operators))?;
5137        if let Some(drop_behavior) = &self.drop_behavior {
5138            write!(f, " {}", drop_behavior)?;
5139        }
5140        Ok(())
5141    }
5142}
5143
5144impl Spanned for DropOperator {
5145    fn span(&self) -> Span {
5146        Span::empty()
5147    }
5148}
5149
5150/// `DROP OPERATOR FAMILY` statement
5151/// See <https://www.postgresql.org/docs/current/sql-dropopfamily.html>
5152#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5153#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5154#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5155pub struct DropOperatorFamily {
5156    /// `IF EXISTS` clause
5157    pub if_exists: bool,
5158    /// One or more operator families to drop
5159    pub names: Vec<ObjectName>,
5160    /// Index method (btree, hash, gist, gin, etc.)
5161    pub using: Ident,
5162    /// `CASCADE or RESTRICT`
5163    pub drop_behavior: Option<DropBehavior>,
5164}
5165
5166impl fmt::Display for DropOperatorFamily {
5167    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5168        write!(f, "DROP OPERATOR FAMILY")?;
5169        if self.if_exists {
5170            write!(f, " IF EXISTS")?;
5171        }
5172        write!(f, " {}", display_comma_separated(&self.names))?;
5173        write!(f, " USING {}", self.using)?;
5174        if let Some(drop_behavior) = &self.drop_behavior {
5175            write!(f, " {}", drop_behavior)?;
5176        }
5177        Ok(())
5178    }
5179}
5180
5181impl Spanned for DropOperatorFamily {
5182    fn span(&self) -> Span {
5183        Span::empty()
5184    }
5185}
5186
5187/// `DROP OPERATOR CLASS` statement
5188/// See <https://www.postgresql.org/docs/current/sql-dropopclass.html>
5189#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5190#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5191#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5192pub struct DropOperatorClass {
5193    /// `IF EXISTS` clause
5194    pub if_exists: bool,
5195    /// One or more operator classes to drop
5196    pub names: Vec<ObjectName>,
5197    /// Index method (btree, hash, gist, gin, etc.)
5198    pub using: Ident,
5199    /// `CASCADE or RESTRICT`
5200    pub drop_behavior: Option<DropBehavior>,
5201}
5202
5203impl fmt::Display for DropOperatorClass {
5204    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5205        write!(f, "DROP OPERATOR CLASS")?;
5206        if self.if_exists {
5207            write!(f, " IF EXISTS")?;
5208        }
5209        write!(f, " {}", display_comma_separated(&self.names))?;
5210        write!(f, " USING {}", self.using)?;
5211        if let Some(drop_behavior) = &self.drop_behavior {
5212            write!(f, " {}", drop_behavior)?;
5213        }
5214        Ok(())
5215    }
5216}
5217
5218impl Spanned for DropOperatorClass {
5219    fn span(&self) -> Span {
5220        Span::empty()
5221    }
5222}
5223
5224/// An item in an ALTER OPERATOR FAMILY ADD statement
5225#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5226#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5227#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5228pub enum OperatorFamilyItem {
5229    /// `OPERATOR` clause in an operator family modification.
5230    Operator {
5231        /// Strategy number for the operator.
5232        strategy_number: u64,
5233        /// Operator name referenced by this entry.
5234        operator_name: ObjectName,
5235        /// Operator argument types.
5236        op_types: Vec<DataType>,
5237        /// Optional purpose such as `FOR SEARCH` or `FOR ORDER BY`.
5238        purpose: Option<OperatorPurpose>,
5239    },
5240    /// `FUNCTION` clause in an operator family modification.
5241    Function {
5242        /// Support function number.
5243        support_number: u64,
5244        /// Optional operator argument types for the function.
5245        op_types: Option<Vec<DataType>>,
5246        /// Function name for the support function.
5247        function_name: ObjectName,
5248        /// Function argument types.
5249        argument_types: Vec<DataType>,
5250    },
5251}
5252
5253/// An item in an ALTER OPERATOR FAMILY DROP statement
5254#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5255#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5256#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5257pub enum OperatorFamilyDropItem {
5258    /// `OPERATOR` clause for DROP within an operator family.
5259    Operator {
5260        /// Strategy number for the operator.
5261        strategy_number: u64,
5262        /// Operator argument types.
5263        op_types: Vec<DataType>,
5264    },
5265    /// `FUNCTION` clause for DROP within an operator family.
5266    Function {
5267        /// Support function number.
5268        support_number: u64,
5269        /// Operator argument types for the function.
5270        op_types: Vec<DataType>,
5271    },
5272}
5273
5274impl fmt::Display for OperatorFamilyItem {
5275    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5276        match self {
5277            OperatorFamilyItem::Operator {
5278                strategy_number,
5279                operator_name,
5280                op_types,
5281                purpose,
5282            } => {
5283                write!(
5284                    f,
5285                    "OPERATOR {strategy_number} {operator_name} ({})",
5286                    display_comma_separated(op_types)
5287                )?;
5288                if let Some(purpose) = purpose {
5289                    write!(f, " {purpose}")?;
5290                }
5291                Ok(())
5292            }
5293            OperatorFamilyItem::Function {
5294                support_number,
5295                op_types,
5296                function_name,
5297                argument_types,
5298            } => {
5299                write!(f, "FUNCTION {support_number}")?;
5300                if let Some(types) = op_types {
5301                    write!(f, " ({})", display_comma_separated(types))?;
5302                }
5303                write!(f, " {function_name}")?;
5304                if !argument_types.is_empty() {
5305                    write!(f, "({})", display_comma_separated(argument_types))?;
5306                }
5307                Ok(())
5308            }
5309        }
5310    }
5311}
5312
5313impl fmt::Display for OperatorFamilyDropItem {
5314    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5315        match self {
5316            OperatorFamilyDropItem::Operator {
5317                strategy_number,
5318                op_types,
5319            } => {
5320                write!(
5321                    f,
5322                    "OPERATOR {strategy_number} ({})",
5323                    display_comma_separated(op_types)
5324                )
5325            }
5326            OperatorFamilyDropItem::Function {
5327                support_number,
5328                op_types,
5329            } => {
5330                write!(
5331                    f,
5332                    "FUNCTION {support_number} ({})",
5333                    display_comma_separated(op_types)
5334                )
5335            }
5336        }
5337    }
5338}
5339
5340/// `ALTER OPERATOR FAMILY` statement
5341/// See <https://www.postgresql.org/docs/current/sql-alteropfamily.html>
5342#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5343#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5344#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5345pub struct AlterOperatorFamily {
5346    /// Operator family name (can be schema-qualified)
5347    pub name: ObjectName,
5348    /// Index method (btree, hash, gist, gin, etc.)
5349    pub using: Ident,
5350    /// The operation to perform
5351    pub operation: AlterOperatorFamilyOperation,
5352}
5353
5354/// An [AlterOperatorFamily] operation
5355#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5356#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5357#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5358pub enum AlterOperatorFamilyOperation {
5359    /// `ADD { OPERATOR ... | FUNCTION ... } [, ...]`
5360    Add {
5361        /// List of operator family items to add
5362        items: Vec<OperatorFamilyItem>,
5363    },
5364    /// `DROP { OPERATOR ... | FUNCTION ... } [, ...]`
5365    Drop {
5366        /// List of operator family items to drop
5367        items: Vec<OperatorFamilyDropItem>,
5368    },
5369    /// `RENAME TO new_name`
5370    RenameTo {
5371        /// The new name for the operator family.
5372        new_name: ObjectName,
5373    },
5374    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
5375    OwnerTo(Owner),
5376    /// `SET SCHEMA new_schema`
5377    SetSchema {
5378        /// The target schema name.
5379        schema_name: ObjectName,
5380    },
5381}
5382
5383impl fmt::Display for AlterOperatorFamily {
5384    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5385        write!(
5386            f,
5387            "ALTER OPERATOR FAMILY {} USING {}",
5388            self.name, self.using
5389        )?;
5390        write!(f, " {}", self.operation)
5391    }
5392}
5393
5394impl fmt::Display for AlterOperatorFamilyOperation {
5395    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5396        match self {
5397            AlterOperatorFamilyOperation::Add { items } => {
5398                write!(f, "ADD {}", display_comma_separated(items))
5399            }
5400            AlterOperatorFamilyOperation::Drop { items } => {
5401                write!(f, "DROP {}", display_comma_separated(items))
5402            }
5403            AlterOperatorFamilyOperation::RenameTo { new_name } => {
5404                write!(f, "RENAME TO {new_name}")
5405            }
5406            AlterOperatorFamilyOperation::OwnerTo(owner) => {
5407                write!(f, "OWNER TO {owner}")
5408            }
5409            AlterOperatorFamilyOperation::SetSchema { schema_name } => {
5410                write!(f, "SET SCHEMA {schema_name}")
5411            }
5412        }
5413    }
5414}
5415
5416impl Spanned for AlterOperatorFamily {
5417    fn span(&self) -> Span {
5418        Span::empty()
5419    }
5420}
5421
5422/// `ALTER OPERATOR CLASS` statement
5423/// See <https://www.postgresql.org/docs/current/sql-alteropclass.html>
5424#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5425#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5426#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5427pub struct AlterOperatorClass {
5428    /// Operator class name (can be schema-qualified)
5429    pub name: ObjectName,
5430    /// Index method (btree, hash, gist, gin, etc.)
5431    pub using: Ident,
5432    /// The operation to perform
5433    pub operation: AlterOperatorClassOperation,
5434}
5435
5436/// An [AlterOperatorClass] operation
5437#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5438#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5439#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5440pub enum AlterOperatorClassOperation {
5441    /// `RENAME TO new_name`
5442    /// Rename the operator class to a new name.
5443    RenameTo {
5444        /// The new name for the operator class.
5445        new_name: ObjectName,
5446    },
5447    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
5448    OwnerTo(Owner),
5449    /// `SET SCHEMA new_schema`
5450    /// Set the schema for the operator class.
5451    SetSchema {
5452        /// The target schema name.
5453        schema_name: ObjectName,
5454    },
5455}
5456
5457impl fmt::Display for AlterOperatorClass {
5458    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5459        write!(f, "ALTER OPERATOR CLASS {} USING {}", self.name, self.using)?;
5460        write!(f, " {}", self.operation)
5461    }
5462}
5463
5464impl fmt::Display for AlterOperatorClassOperation {
5465    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5466        match self {
5467            AlterOperatorClassOperation::RenameTo { new_name } => {
5468                write!(f, "RENAME TO {new_name}")
5469            }
5470            AlterOperatorClassOperation::OwnerTo(owner) => {
5471                write!(f, "OWNER TO {owner}")
5472            }
5473            AlterOperatorClassOperation::SetSchema { schema_name } => {
5474                write!(f, "SET SCHEMA {schema_name}")
5475            }
5476        }
5477    }
5478}
5479
5480impl Spanned for AlterOperatorClass {
5481    fn span(&self) -> Span {
5482        Span::empty()
5483    }
5484}
5485
5486/// `ALTER FUNCTION` / `ALTER AGGREGATE` statement.
5487#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5488#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5489#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5490pub struct AlterFunction {
5491    /// Object type being altered.
5492    pub kind: AlterFunctionKind,
5493    /// Function or aggregate signature.
5494    pub function: FunctionDesc,
5495    /// `ORDER BY` argument list for aggregate signatures.
5496    ///
5497    /// This is only used for `ALTER AGGREGATE`.
5498    pub aggregate_order_by: Option<Vec<OperateFunctionArg>>,
5499    /// Whether the aggregate signature uses `*`.
5500    ///
5501    /// This is only used for `ALTER AGGREGATE`.
5502    pub aggregate_star: bool,
5503    /// Operation applied to the object.
5504    pub operation: AlterFunctionOperation,
5505}
5506
5507/// Function-like object type used by [`AlterFunction`].
5508#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5509#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5510#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5511pub enum AlterFunctionKind {
5512    /// `FUNCTION`
5513    Function,
5514    /// `AGGREGATE`
5515    Aggregate,
5516}
5517
5518impl fmt::Display for AlterFunctionKind {
5519    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5520        match self {
5521            Self::Function => write!(f, "FUNCTION"),
5522            Self::Aggregate => write!(f, "AGGREGATE"),
5523        }
5524    }
5525}
5526
5527/// Operation for `ALTER FUNCTION` / `ALTER AGGREGATE`.
5528#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5529#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5530#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5531pub enum AlterFunctionOperation {
5532    /// `RENAME TO new_name`
5533    RenameTo {
5534        /// New unqualified function or aggregate name.
5535        new_name: Ident,
5536    },
5537    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
5538    OwnerTo(Owner),
5539    /// `SET SCHEMA schema_name`
5540    SetSchema {
5541        /// The target schema name.
5542        schema_name: ObjectName,
5543    },
5544    /// `[ NO ] DEPENDS ON EXTENSION extension_name`
5545    DependsOnExtension {
5546        /// `true` when `NO DEPENDS ON EXTENSION`.
5547        no: bool,
5548        /// Extension name.
5549        extension_name: ObjectName,
5550    },
5551    /// `action [ ... ] [ RESTRICT ]` (function only).
5552    Actions {
5553        /// One or more function actions.
5554        actions: Vec<AlterFunctionAction>,
5555        /// Whether `RESTRICT` is present.
5556        restrict: bool,
5557    },
5558}
5559
5560/// Function action in `ALTER FUNCTION ... action [ ... ] [ RESTRICT ]`.
5561#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5562#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5563#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5564pub enum AlterFunctionAction {
5565    /// `CALLED ON NULL INPUT` / `RETURNS NULL ON NULL INPUT` / `STRICT`
5566    CalledOnNull(FunctionCalledOnNull),
5567    /// `IMMUTABLE` / `STABLE` / `VOLATILE`
5568    Behavior(FunctionBehavior),
5569    /// `[ NOT ] LEAKPROOF`
5570    Leakproof(bool),
5571    /// `[ EXTERNAL ] SECURITY { DEFINER | INVOKER }`
5572    Security {
5573        /// Whether the optional `EXTERNAL` keyword was present.
5574        external: bool,
5575        /// Security mode.
5576        security: FunctionSecurity,
5577    },
5578    /// `PARALLEL { UNSAFE | RESTRICTED | SAFE }`
5579    Parallel(FunctionParallel),
5580    /// `COST execution_cost`
5581    Cost(Expr),
5582    /// `ROWS result_rows`
5583    Rows(Expr),
5584    /// `SUPPORT support_function`
5585    Support(ObjectName),
5586    /// `SET configuration_parameter { TO | = } { value | DEFAULT }`
5587    /// or `SET configuration_parameter FROM CURRENT`
5588    Set(FunctionDefinitionSetParam),
5589    /// `RESET configuration_parameter` or `RESET ALL`
5590    Reset(ResetConfig),
5591}
5592
5593impl fmt::Display for AlterFunction {
5594    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5595        write!(f, "ALTER {} ", self.kind)?;
5596        match self.kind {
5597            AlterFunctionKind::Function => {
5598                write!(f, "{} ", self.function)?;
5599            }
5600            AlterFunctionKind::Aggregate => {
5601                write!(f, "{}(", self.function.name)?;
5602                if self.aggregate_star {
5603                    write!(f, "*")?;
5604                } else {
5605                    if let Some(args) = &self.function.args {
5606                        write!(f, "{}", display_comma_separated(args))?;
5607                    }
5608                    if let Some(order_by_args) = &self.aggregate_order_by {
5609                        if self
5610                            .function
5611                            .args
5612                            .as_ref()
5613                            .is_some_and(|args| !args.is_empty())
5614                        {
5615                            write!(f, " ")?;
5616                        }
5617                        write!(f, "ORDER BY {}", display_comma_separated(order_by_args))?;
5618                    }
5619                }
5620                write!(f, ") ")?;
5621            }
5622        }
5623        write!(f, "{}", self.operation)
5624    }
5625}
5626
5627impl fmt::Display for AlterFunctionOperation {
5628    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5629        match self {
5630            AlterFunctionOperation::RenameTo { new_name } => {
5631                write!(f, "RENAME TO {new_name}")
5632            }
5633            AlterFunctionOperation::OwnerTo(owner) => write!(f, "OWNER TO {owner}"),
5634            AlterFunctionOperation::SetSchema { schema_name } => {
5635                write!(f, "SET SCHEMA {schema_name}")
5636            }
5637            AlterFunctionOperation::DependsOnExtension { no, extension_name } => {
5638                if *no {
5639                    write!(f, "NO DEPENDS ON EXTENSION {extension_name}")
5640                } else {
5641                    write!(f, "DEPENDS ON EXTENSION {extension_name}")
5642                }
5643            }
5644            AlterFunctionOperation::Actions { actions, restrict } => {
5645                write!(f, "{}", display_separated(actions, " "))?;
5646                if *restrict {
5647                    write!(f, " RESTRICT")?;
5648                }
5649                Ok(())
5650            }
5651        }
5652    }
5653}
5654
5655impl fmt::Display for AlterFunctionAction {
5656    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5657        match self {
5658            AlterFunctionAction::CalledOnNull(called_on_null) => write!(f, "{called_on_null}"),
5659            AlterFunctionAction::Behavior(behavior) => write!(f, "{behavior}"),
5660            AlterFunctionAction::Leakproof(leakproof) => {
5661                if *leakproof {
5662                    write!(f, "LEAKPROOF")
5663                } else {
5664                    write!(f, "NOT LEAKPROOF")
5665                }
5666            }
5667            AlterFunctionAction::Security { external, security } => {
5668                if *external {
5669                    write!(f, "EXTERNAL ")?;
5670                }
5671                write!(f, "{security}")
5672            }
5673            AlterFunctionAction::Parallel(parallel) => write!(f, "{parallel}"),
5674            AlterFunctionAction::Cost(execution_cost) => write!(f, "COST {execution_cost}"),
5675            AlterFunctionAction::Rows(result_rows) => write!(f, "ROWS {result_rows}"),
5676            AlterFunctionAction::Support(support_function) => {
5677                write!(f, "SUPPORT {support_function}")
5678            }
5679            AlterFunctionAction::Set(set_param) => write!(f, "{set_param}"),
5680            AlterFunctionAction::Reset(reset_config) => match reset_config {
5681                ResetConfig::ALL => write!(f, "RESET ALL"),
5682                ResetConfig::ConfigName(name) => write!(f, "RESET {name}"),
5683            },
5684        }
5685    }
5686}
5687
5688impl Spanned for AlterFunction {
5689    fn span(&self) -> Span {
5690        Span::empty()
5691    }
5692}
5693
5694/// Text search object kind.
5695///
5696/// See [PostgreSQL](https://www.postgresql.org/docs/current/textsearch-intro.html).
5697#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
5698#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5699#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5700pub enum TextSearchObjectType {
5701    /// `DICTIONARY`
5702    Dictionary,
5703    /// `CONFIGURATION`
5704    Configuration,
5705    /// `TEMPLATE`
5706    Template,
5707    /// `PARSER`
5708    Parser,
5709}
5710
5711impl fmt::Display for TextSearchObjectType {
5712    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5713        match self {
5714            TextSearchObjectType::Dictionary => write!(f, "DICTIONARY"),
5715            TextSearchObjectType::Configuration => write!(f, "CONFIGURATION"),
5716            TextSearchObjectType::Template => write!(f, "TEMPLATE"),
5717            TextSearchObjectType::Parser => write!(f, "PARSER"),
5718        }
5719    }
5720}
5721
5722/// `CREATE TEXT SEARCH ...` statement.
5723///
5724/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createtsdictionary.html).
5725#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5726#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5727#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5728pub struct CreateTextSearch {
5729    /// The specific text search object type.
5730    pub object_type: TextSearchObjectType,
5731    /// Object name.
5732    pub name: ObjectName,
5733    /// Parenthesized options.
5734    pub options: Vec<SqlOption>,
5735}
5736
5737impl fmt::Display for CreateTextSearch {
5738    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5739        write!(
5740            f,
5741            "CREATE TEXT SEARCH {} {} ({})",
5742            self.object_type,
5743            self.name,
5744            display_comma_separated(&self.options)
5745        )
5746    }
5747}
5748
5749impl Spanned for CreateTextSearch {
5750    fn span(&self) -> Span {
5751        Span::empty()
5752    }
5753}
5754
5755/// Option assignment used by `ALTER TEXT SEARCH ... ( ... )`.
5756///
5757/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-altertsdictionary.html).
5758#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5759#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5760#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5761pub struct AlterTextSearchOption {
5762    /// Option name.
5763    pub key: Ident,
5764    /// Optional value (`option [= value]`).
5765    pub value: Option<Expr>,
5766}
5767
5768impl fmt::Display for AlterTextSearchOption {
5769    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5770        match &self.value {
5771            Some(value) => write!(f, "{} = {}", self.key, value),
5772            None => write!(f, "{}", self.key),
5773        }
5774    }
5775}
5776
5777/// Operation for `ALTER TEXT SEARCH ...`.
5778///
5779/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-altertsdictionary.html).
5780#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5781#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5782#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5783pub enum AlterTextSearchOperation {
5784    /// `RENAME TO new_name`
5785    RenameTo {
5786        /// New name.
5787        new_name: Ident,
5788    },
5789    /// `OWNER TO ...`
5790    OwnerTo(Owner),
5791    /// `SET SCHEMA schema_name`
5792    SetSchema {
5793        /// Target schema.
5794        schema_name: ObjectName,
5795    },
5796    /// `( option [= value] [, ...] )`
5797    SetOptions {
5798        /// Text search options to apply.
5799        options: Vec<AlterTextSearchOption>,
5800    },
5801}
5802
5803impl fmt::Display for AlterTextSearchOperation {
5804    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5805        match self {
5806            AlterTextSearchOperation::RenameTo { new_name } => write!(f, "RENAME TO {new_name}"),
5807            AlterTextSearchOperation::OwnerTo(owner) => write!(f, "OWNER TO {owner}"),
5808            AlterTextSearchOperation::SetSchema { schema_name } => {
5809                write!(f, "SET SCHEMA {schema_name}")
5810            }
5811            AlterTextSearchOperation::SetOptions { options } => {
5812                write!(f, "({})", display_comma_separated(options))
5813            }
5814        }
5815    }
5816}
5817
5818/// `ALTER TEXT SEARCH ...` statement.
5819///
5820/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-altertsdictionary.html).
5821#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5822#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5823#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5824pub struct AlterTextSearch {
5825    /// The specific text search object type.
5826    pub object_type: TextSearchObjectType,
5827    /// Object name.
5828    pub name: ObjectName,
5829    /// Operation to apply.
5830    pub operation: AlterTextSearchOperation,
5831}
5832
5833impl fmt::Display for AlterTextSearch {
5834    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5835        write!(
5836            f,
5837            "ALTER TEXT SEARCH {} {} {}",
5838            self.object_type, self.name, self.operation
5839        )
5840    }
5841}
5842
5843impl Spanned for AlterTextSearch {
5844    fn span(&self) -> Span {
5845        Span::empty()
5846    }
5847}
5848
5849/// CREATE POLICY statement.
5850///
5851/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createpolicy.html)
5852#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5853#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5854#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5855pub struct CreatePolicy {
5856    /// Name of the policy.
5857    pub name: Ident,
5858    /// Table the policy is defined on.
5859    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
5860    pub table_name: ObjectName,
5861    /// Optional policy type (e.g., `PERMISSIVE` / `RESTRICTIVE`).
5862    pub policy_type: Option<CreatePolicyType>,
5863    /// Optional command the policy applies to (e.g., `SELECT`).
5864    pub command: Option<CreatePolicyCommand>,
5865    /// Optional list of grantee owners.
5866    pub to: Option<Vec<Owner>>,
5867    /// Optional expression for the `USING` clause.
5868    pub using: Option<Expr>,
5869    /// Optional expression for the `WITH CHECK` clause.
5870    pub with_check: Option<Expr>,
5871}
5872
5873impl fmt::Display for CreatePolicy {
5874    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5875        write!(
5876            f,
5877            "CREATE POLICY {name} ON {table_name}",
5878            name = self.name,
5879            table_name = self.table_name,
5880        )?;
5881        if let Some(ref policy_type) = self.policy_type {
5882            write!(f, " AS {policy_type}")?;
5883        }
5884        if let Some(ref command) = self.command {
5885            write!(f, " FOR {command}")?;
5886        }
5887        if let Some(ref to) = self.to {
5888            write!(f, " TO {}", display_comma_separated(to))?;
5889        }
5890        if let Some(ref using) = self.using {
5891            write!(f, " USING ({using})")?;
5892        }
5893        if let Some(ref with_check) = self.with_check {
5894            write!(f, " WITH CHECK ({with_check})")?;
5895        }
5896        Ok(())
5897    }
5898}
5899
5900/// Policy type for a `CREATE POLICY` statement.
5901/// ```sql
5902/// AS [ PERMISSIVE | RESTRICTIVE ]
5903/// ```
5904/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createpolicy.html)
5905#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
5906#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5907#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5908pub enum CreatePolicyType {
5909    /// Policy allows operations unless explicitly denied.
5910    Permissive,
5911    /// Policy denies operations unless explicitly allowed.
5912    Restrictive,
5913}
5914
5915impl fmt::Display for CreatePolicyType {
5916    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5917        match self {
5918            CreatePolicyType::Permissive => write!(f, "PERMISSIVE"),
5919            CreatePolicyType::Restrictive => write!(f, "RESTRICTIVE"),
5920        }
5921    }
5922}
5923
5924/// Command that a policy can apply to (FOR clause).
5925/// ```sql
5926/// FOR [ALL | SELECT | INSERT | UPDATE | DELETE]
5927/// ```
5928/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createpolicy.html)
5929#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
5930#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5931#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5932pub enum CreatePolicyCommand {
5933    /// Applies to all commands.
5934    All,
5935    /// Applies to SELECT.
5936    Select,
5937    /// Applies to INSERT.
5938    Insert,
5939    /// Applies to UPDATE.
5940    Update,
5941    /// Applies to DELETE.
5942    Delete,
5943}
5944
5945impl fmt::Display for CreatePolicyCommand {
5946    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5947        match self {
5948            CreatePolicyCommand::All => write!(f, "ALL"),
5949            CreatePolicyCommand::Select => write!(f, "SELECT"),
5950            CreatePolicyCommand::Insert => write!(f, "INSERT"),
5951            CreatePolicyCommand::Update => write!(f, "UPDATE"),
5952            CreatePolicyCommand::Delete => write!(f, "DELETE"),
5953        }
5954    }
5955}
5956
5957/// DROP POLICY statement.
5958///
5959/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-droppolicy.html)
5960#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5961#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5962#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5963pub struct DropPolicy {
5964    /// `true` when `IF EXISTS` was present.
5965    pub if_exists: bool,
5966    /// Name of the policy to drop.
5967    pub name: Ident,
5968    /// Name of the table the policy applies to.
5969    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
5970    pub table_name: ObjectName,
5971    /// Optional drop behavior (`CASCADE` or `RESTRICT`).
5972    pub drop_behavior: Option<DropBehavior>,
5973}
5974
5975impl fmt::Display for DropPolicy {
5976    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5977        write!(
5978            f,
5979            "DROP POLICY {if_exists}{name} ON {table_name}",
5980            if_exists = if self.if_exists { "IF EXISTS " } else { "" },
5981            name = self.name,
5982            table_name = self.table_name
5983        )?;
5984        if let Some(ref behavior) = self.drop_behavior {
5985            write!(f, " {behavior}")?;
5986        }
5987        Ok(())
5988    }
5989}
5990
5991impl From<CreatePolicy> for crate::ast::Statement {
5992    fn from(v: CreatePolicy) -> Self {
5993        crate::ast::Statement::CreatePolicy(v)
5994    }
5995}
5996
5997impl From<DropPolicy> for crate::ast::Statement {
5998    fn from(v: DropPolicy) -> Self {
5999        crate::ast::Statement::DropPolicy(v)
6000    }
6001}
6002
6003/// ALTER POLICY statement.
6004///
6005/// ```sql
6006/// ALTER POLICY <NAME> ON <TABLE NAME> [<OPERATION>]
6007/// ```
6008/// (Postgresql-specific)
6009#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
6010#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6011#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6012pub struct AlterPolicy {
6013    /// Policy name to alter.
6014    pub name: Ident,
6015    /// Target table name the policy is defined on.
6016    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
6017    pub table_name: ObjectName,
6018    /// Optional operation specific to the policy alteration.
6019    pub operation: AlterPolicyOperation,
6020}
6021
6022impl fmt::Display for AlterPolicy {
6023    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6024        write!(
6025            f,
6026            "ALTER POLICY {name} ON {table_name}{operation}",
6027            name = self.name,
6028            table_name = self.table_name,
6029            operation = self.operation
6030        )
6031    }
6032}
6033
6034impl From<AlterPolicy> for crate::ast::Statement {
6035    fn from(v: AlterPolicy) -> Self {
6036        crate::ast::Statement::AlterPolicy(v)
6037    }
6038}