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