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, RowAccessPolicy, SequenceOptions,
51    Spanned, SqlOption, StorageSerializationPolicy, TableVersion, Tag, TriggerEvent,
52    TriggerExecBody, TriggerObject, TriggerPeriod, TriggerReferencing, Value, ValueWithSpan,
53    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    pub column: OrderByExpr,
65    pub operator_class: Option<ObjectName>,
66}
67
68impl From<Ident> for IndexColumn {
69    fn from(c: Ident) -> Self {
70        Self {
71            column: OrderByExpr::from(c),
72            operator_class: None,
73        }
74    }
75}
76
77impl<'a> From<&'a str> for IndexColumn {
78    fn from(c: &'a str) -> Self {
79        let ident = Ident::new(c);
80        ident.into()
81    }
82}
83
84impl fmt::Display for IndexColumn {
85    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86        write!(f, "{}", self.column)?;
87        if let Some(operator_class) = &self.operator_class {
88            write!(f, " {operator_class}")?;
89        }
90        Ok(())
91    }
92}
93
94/// ALTER TABLE operation REPLICA IDENTITY values
95/// See [Postgres ALTER TABLE docs](https://www.postgresql.org/docs/current/sql-altertable.html)
96#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
97#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
98#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
99pub enum ReplicaIdentity {
100    None,
101    Full,
102    Default,
103    Index(Ident),
104}
105
106impl fmt::Display for ReplicaIdentity {
107    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108        match self {
109            ReplicaIdentity::None => f.write_str("NONE"),
110            ReplicaIdentity::Full => f.write_str("FULL"),
111            ReplicaIdentity::Default => f.write_str("DEFAULT"),
112            ReplicaIdentity::Index(idx) => write!(f, "USING INDEX {idx}"),
113        }
114    }
115}
116
117/// An `ALTER TABLE` (`Statement::AlterTable`) operation
118#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
119#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
120#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
121pub enum AlterTableOperation {
122    /// `ADD <table_constraint> [NOT VALID]`
123    AddConstraint {
124        constraint: TableConstraint,
125        not_valid: bool,
126    },
127    /// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
128    AddColumn {
129        /// `[COLUMN]`.
130        column_keyword: bool,
131        /// `[IF NOT EXISTS]`
132        if_not_exists: bool,
133        /// <column_def>.
134        column_def: ColumnDef,
135        /// MySQL `ALTER TABLE` only  [FIRST | AFTER column_name]
136        column_position: Option<MySQLColumnPosition>,
137    },
138    /// `ADD PROJECTION [IF NOT EXISTS] name ( SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY])`
139    ///
140    /// Note: this is a ClickHouse-specific operation.
141    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#add-projection)
142    AddProjection {
143        if_not_exists: bool,
144        name: Ident,
145        select: ProjectionSelect,
146    },
147    /// `DROP PROJECTION [IF EXISTS] name`
148    ///
149    /// Note: this is a ClickHouse-specific operation.
150    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#drop-projection)
151    DropProjection {
152        if_exists: bool,
153        name: Ident,
154    },
155    /// `MATERIALIZE PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
156    ///
157    ///  Note: this is a ClickHouse-specific operation.
158    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#materialize-projection)
159    MaterializeProjection {
160        if_exists: bool,
161        name: Ident,
162        partition: Option<Ident>,
163    },
164    /// `CLEAR PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
165    ///
166    /// Note: this is a ClickHouse-specific operation.
167    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#clear-projection)
168    ClearProjection {
169        if_exists: bool,
170        name: Ident,
171        partition: Option<Ident>,
172    },
173    /// `DISABLE ROW LEVEL SECURITY`
174    ///
175    /// Note: this is a PostgreSQL-specific operation.
176    DisableRowLevelSecurity,
177    /// `DISABLE RULE rewrite_rule_name`
178    ///
179    /// Note: this is a PostgreSQL-specific operation.
180    DisableRule {
181        name: Ident,
182    },
183    /// `DISABLE TRIGGER [ trigger_name | ALL | USER ]`
184    ///
185    /// Note: this is a PostgreSQL-specific operation.
186    DisableTrigger {
187        name: Ident,
188    },
189    /// `DROP CONSTRAINT [ IF EXISTS ] <name>`
190    DropConstraint {
191        if_exists: bool,
192        name: Ident,
193        drop_behavior: Option<DropBehavior>,
194    },
195    /// `DROP [ COLUMN ] [ IF EXISTS ] <column_name> [ , <column_name>, ... ] [ CASCADE ]`
196    DropColumn {
197        has_column_keyword: bool,
198        column_names: Vec<Ident>,
199        if_exists: bool,
200        drop_behavior: Option<DropBehavior>,
201    },
202    /// `ATTACH PART|PARTITION <partition_expr>`
203    /// Note: this is a ClickHouse-specific operation, please refer to
204    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
205    AttachPartition {
206        // PART is not a short form of PARTITION, it's a separate keyword
207        // which represents a physical file on disk and partition is a logical entity.
208        partition: Partition,
209    },
210    /// `DETACH PART|PARTITION <partition_expr>`
211    /// Note: this is a ClickHouse-specific operation, please refer to
212    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#detach-partitionpart)
213    DetachPartition {
214        // See `AttachPartition` for more details
215        partition: Partition,
216    },
217    /// `FREEZE PARTITION <partition_expr>`
218    /// Note: this is a ClickHouse-specific operation, please refer to
219    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#freeze-partition)
220    FreezePartition {
221        partition: Partition,
222        with_name: Option<Ident>,
223    },
224    /// `UNFREEZE PARTITION <partition_expr>`
225    /// Note: this is a ClickHouse-specific operation, please refer to
226    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#unfreeze-partition)
227    UnfreezePartition {
228        partition: Partition,
229        with_name: Option<Ident>,
230    },
231    /// `DROP PRIMARY KEY`
232    ///
233    /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/alter-table.html)
234    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constraints-drop)
235    DropPrimaryKey {
236        drop_behavior: Option<DropBehavior>,
237    },
238    /// `DROP FOREIGN KEY <fk_symbol>`
239    ///
240    /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/alter-table.html)
241    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constraints-drop)
242    DropForeignKey {
243        name: Ident,
244        drop_behavior: Option<DropBehavior>,
245    },
246    /// `DROP INDEX <index_name>`
247    ///
248    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
249    DropIndex {
250        name: Ident,
251    },
252    /// `ENABLE ALWAYS RULE rewrite_rule_name`
253    ///
254    /// Note: this is a PostgreSQL-specific operation.
255    EnableAlwaysRule {
256        name: Ident,
257    },
258    /// `ENABLE ALWAYS TRIGGER trigger_name`
259    ///
260    /// Note: this is a PostgreSQL-specific operation.
261    EnableAlwaysTrigger {
262        name: Ident,
263    },
264    /// `ENABLE REPLICA RULE rewrite_rule_name`
265    ///
266    /// Note: this is a PostgreSQL-specific operation.
267    EnableReplicaRule {
268        name: Ident,
269    },
270    /// `ENABLE REPLICA TRIGGER trigger_name`
271    ///
272    /// Note: this is a PostgreSQL-specific operation.
273    EnableReplicaTrigger {
274        name: Ident,
275    },
276    /// `ENABLE ROW LEVEL SECURITY`
277    ///
278    /// Note: this is a PostgreSQL-specific operation.
279    EnableRowLevelSecurity,
280    /// `ENABLE RULE rewrite_rule_name`
281    ///
282    /// Note: this is a PostgreSQL-specific operation.
283    EnableRule {
284        name: Ident,
285    },
286    /// `ENABLE TRIGGER [ trigger_name | ALL | USER ]`
287    ///
288    /// Note: this is a PostgreSQL-specific operation.
289    EnableTrigger {
290        name: Ident,
291    },
292    /// `RENAME TO PARTITION (partition=val)`
293    RenamePartitions {
294        old_partitions: Vec<Expr>,
295        new_partitions: Vec<Expr>,
296    },
297    /// REPLICA IDENTITY { DEFAULT | USING INDEX index_name | FULL | NOTHING }
298    ///
299    /// Note: this is a PostgreSQL-specific operation.
300    /// Please refer to [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
301    ReplicaIdentity {
302        identity: ReplicaIdentity,
303    },
304    /// Add Partitions
305    AddPartitions {
306        if_not_exists: bool,
307        new_partitions: Vec<Partition>,
308    },
309    DropPartitions {
310        partitions: Vec<Expr>,
311        if_exists: bool,
312    },
313    /// `RENAME [ COLUMN ] <old_column_name> TO <new_column_name>`
314    RenameColumn {
315        old_column_name: Ident,
316        new_column_name: Ident,
317    },
318    /// `RENAME TO <table_name>`
319    RenameTable {
320        table_name: RenameTableNameKind,
321    },
322    // CHANGE [ COLUMN ] <old_name> <new_name> <data_type> [ <options> ]
323    ChangeColumn {
324        old_name: Ident,
325        new_name: Ident,
326        data_type: DataType,
327        options: Vec<ColumnOption>,
328        /// MySQL `ALTER TABLE` only  [FIRST | AFTER column_name]
329        column_position: Option<MySQLColumnPosition>,
330    },
331    // CHANGE [ COLUMN ] <col_name> <data_type> [ <options> ]
332    ModifyColumn {
333        col_name: Ident,
334        data_type: DataType,
335        options: Vec<ColumnOption>,
336        /// MySQL `ALTER TABLE` only  [FIRST | AFTER column_name]
337        column_position: Option<MySQLColumnPosition>,
338    },
339    /// `RENAME CONSTRAINT <old_constraint_name> TO <new_constraint_name>`
340    ///
341    /// Note: this is a PostgreSQL-specific operation.
342    RenameConstraint {
343        old_name: Ident,
344        new_name: Ident,
345    },
346    /// `ALTER [ COLUMN ]`
347    AlterColumn {
348        column_name: Ident,
349        op: AlterColumnOperation,
350    },
351    /// 'SWAP WITH <table_name>'
352    ///
353    /// Note: this is Snowflake specific <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
354    SwapWith {
355        table_name: ObjectName,
356    },
357    /// 'SET TBLPROPERTIES ( { property_key [ = ] property_val } [, ...] )'
358    SetTblProperties {
359        table_properties: Vec<SqlOption>,
360    },
361    /// `OWNER TO { <new_owner> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
362    ///
363    /// Note: this is PostgreSQL-specific <https://www.postgresql.org/docs/current/sql-altertable.html>
364    OwnerTo {
365        new_owner: Owner,
366    },
367    /// Snowflake table clustering options
368    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-table#clustering-actions-clusteringaction>
369    ClusterBy {
370        exprs: Vec<Expr>,
371    },
372    DropClusteringKey,
373    SuspendRecluster,
374    ResumeRecluster,
375    /// `REFRESH [ '<subpath>' ]`
376    ///
377    /// Note: this is Snowflake specific for dynamic/external tables
378    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-dynamic-table>
379    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
380    Refresh {
381        /// Optional subpath for external table refresh
382        subpath: Option<String>,
383    },
384    /// `SUSPEND`
385    ///
386    /// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
387    Suspend,
388    /// `RESUME`
389    ///
390    /// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
391    Resume,
392    /// `ALGORITHM [=] { DEFAULT | INSTANT | INPLACE | COPY }`
393    ///
394    /// [MySQL]-specific table alter algorithm.
395    ///
396    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
397    Algorithm {
398        equals: bool,
399        algorithm: AlterTableAlgorithm,
400    },
401
402    /// `LOCK [=] { DEFAULT | NONE | SHARED | EXCLUSIVE }`
403    ///
404    /// [MySQL]-specific table alter lock.
405    ///
406    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
407    Lock {
408        equals: bool,
409        lock: AlterTableLock,
410    },
411    /// `AUTO_INCREMENT [=] <value>`
412    ///
413    /// [MySQL]-specific table option for raising current auto increment value.
414    ///
415    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
416    AutoIncrement {
417        equals: bool,
418        value: ValueWithSpan,
419    },
420    /// `VALIDATE CONSTRAINT <name>`
421    ValidateConstraint {
422        name: Ident,
423    },
424    /// Arbitrary parenthesized `SET` options.
425    ///
426    /// Example:
427    /// ```sql
428    /// SET (scale_factor = 0.01, threshold = 500)`
429    /// ```
430    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-altertable.html)
431    SetOptionsParens {
432        options: Vec<SqlOption>,
433    },
434}
435
436/// An `ALTER Policy` (`Statement::AlterPolicy`) operation
437///
438/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
439#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
440#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
441#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
442pub enum AlterPolicyOperation {
443    Rename {
444        new_name: Ident,
445    },
446    Apply {
447        to: Option<Vec<Owner>>,
448        using: Option<Expr>,
449        with_check: Option<Expr>,
450    },
451}
452
453impl fmt::Display for AlterPolicyOperation {
454    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
455        match self {
456            AlterPolicyOperation::Rename { new_name } => {
457                write!(f, " RENAME TO {new_name}")
458            }
459            AlterPolicyOperation::Apply {
460                to,
461                using,
462                with_check,
463            } => {
464                if let Some(to) = to {
465                    write!(f, " TO {}", display_comma_separated(to))?;
466                }
467                if let Some(using) = using {
468                    write!(f, " USING ({using})")?;
469                }
470                if let Some(with_check) = with_check {
471                    write!(f, " WITH CHECK ({with_check})")?;
472                }
473                Ok(())
474            }
475        }
476    }
477}
478
479/// [MySQL] `ALTER TABLE` algorithm.
480///
481/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
482#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
483#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
484#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
485pub enum AlterTableAlgorithm {
486    Default,
487    Instant,
488    Inplace,
489    Copy,
490}
491
492impl fmt::Display for AlterTableAlgorithm {
493    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
494        f.write_str(match self {
495            Self::Default => "DEFAULT",
496            Self::Instant => "INSTANT",
497            Self::Inplace => "INPLACE",
498            Self::Copy => "COPY",
499        })
500    }
501}
502
503/// [MySQL] `ALTER TABLE` lock.
504///
505/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
506#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
507#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
508#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
509pub enum AlterTableLock {
510    Default,
511    None,
512    Shared,
513    Exclusive,
514}
515
516impl fmt::Display for AlterTableLock {
517    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
518        f.write_str(match self {
519            Self::Default => "DEFAULT",
520            Self::None => "NONE",
521            Self::Shared => "SHARED",
522            Self::Exclusive => "EXCLUSIVE",
523        })
524    }
525}
526
527#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
528#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
529#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
530pub enum Owner {
531    Ident(Ident),
532    CurrentRole,
533    CurrentUser,
534    SessionUser,
535}
536
537impl fmt::Display for Owner {
538    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
539        match self {
540            Owner::Ident(ident) => write!(f, "{ident}"),
541            Owner::CurrentRole => write!(f, "CURRENT_ROLE"),
542            Owner::CurrentUser => write!(f, "CURRENT_USER"),
543            Owner::SessionUser => write!(f, "SESSION_USER"),
544        }
545    }
546}
547
548#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
549#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
550#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
551pub enum AlterConnectorOwner {
552    User(Ident),
553    Role(Ident),
554}
555
556impl fmt::Display for AlterConnectorOwner {
557    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
558        match self {
559            AlterConnectorOwner::User(ident) => write!(f, "USER {ident}"),
560            AlterConnectorOwner::Role(ident) => write!(f, "ROLE {ident}"),
561        }
562    }
563}
564
565#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
566#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
567#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
568pub enum AlterIndexOperation {
569    RenameIndex { index_name: ObjectName },
570}
571
572impl fmt::Display for AlterTableOperation {
573    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
574        match self {
575            AlterTableOperation::AddPartitions {
576                if_not_exists,
577                new_partitions,
578            } => write!(
579                f,
580                "ADD{ine} {}",
581                display_separated(new_partitions, " "),
582                ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
583            ),
584            AlterTableOperation::AddConstraint {
585                not_valid,
586                constraint,
587            } => {
588                write!(f, "ADD {constraint}")?;
589                if *not_valid {
590                    write!(f, " NOT VALID")?;
591                }
592                Ok(())
593            }
594            AlterTableOperation::AddColumn {
595                column_keyword,
596                if_not_exists,
597                column_def,
598                column_position,
599            } => {
600                write!(f, "ADD")?;
601                if *column_keyword {
602                    write!(f, " COLUMN")?;
603                }
604                if *if_not_exists {
605                    write!(f, " IF NOT EXISTS")?;
606                }
607                write!(f, " {column_def}")?;
608
609                if let Some(position) = column_position {
610                    write!(f, " {position}")?;
611                }
612
613                Ok(())
614            }
615            AlterTableOperation::AddProjection {
616                if_not_exists,
617                name,
618                select: query,
619            } => {
620                write!(f, "ADD PROJECTION")?;
621                if *if_not_exists {
622                    write!(f, " IF NOT EXISTS")?;
623                }
624                write!(f, " {name} ({query})")
625            }
626            AlterTableOperation::Algorithm { equals, algorithm } => {
627                write!(
628                    f,
629                    "ALGORITHM {}{}",
630                    if *equals { "= " } else { "" },
631                    algorithm
632                )
633            }
634            AlterTableOperation::DropProjection { if_exists, name } => {
635                write!(f, "DROP PROJECTION")?;
636                if *if_exists {
637                    write!(f, " IF EXISTS")?;
638                }
639                write!(f, " {name}")
640            }
641            AlterTableOperation::MaterializeProjection {
642                if_exists,
643                name,
644                partition,
645            } => {
646                write!(f, "MATERIALIZE PROJECTION")?;
647                if *if_exists {
648                    write!(f, " IF EXISTS")?;
649                }
650                write!(f, " {name}")?;
651                if let Some(partition) = partition {
652                    write!(f, " IN PARTITION {partition}")?;
653                }
654                Ok(())
655            }
656            AlterTableOperation::ClearProjection {
657                if_exists,
658                name,
659                partition,
660            } => {
661                write!(f, "CLEAR PROJECTION")?;
662                if *if_exists {
663                    write!(f, " IF EXISTS")?;
664                }
665                write!(f, " {name}")?;
666                if let Some(partition) = partition {
667                    write!(f, " IN PARTITION {partition}")?;
668                }
669                Ok(())
670            }
671            AlterTableOperation::AlterColumn { column_name, op } => {
672                write!(f, "ALTER COLUMN {column_name} {op}")
673            }
674            AlterTableOperation::DisableRowLevelSecurity => {
675                write!(f, "DISABLE ROW LEVEL SECURITY")
676            }
677            AlterTableOperation::DisableRule { name } => {
678                write!(f, "DISABLE RULE {name}")
679            }
680            AlterTableOperation::DisableTrigger { name } => {
681                write!(f, "DISABLE TRIGGER {name}")
682            }
683            AlterTableOperation::DropPartitions {
684                partitions,
685                if_exists,
686            } => write!(
687                f,
688                "DROP{ie} PARTITION ({})",
689                display_comma_separated(partitions),
690                ie = if *if_exists { " IF EXISTS" } else { "" }
691            ),
692            AlterTableOperation::DropConstraint {
693                if_exists,
694                name,
695                drop_behavior,
696            } => {
697                write!(
698                    f,
699                    "DROP CONSTRAINT {}{}",
700                    if *if_exists { "IF EXISTS " } else { "" },
701                    name
702                )?;
703                if let Some(drop_behavior) = drop_behavior {
704                    write!(f, " {drop_behavior}")?;
705                }
706                Ok(())
707            }
708            AlterTableOperation::DropPrimaryKey { drop_behavior } => {
709                write!(f, "DROP PRIMARY KEY")?;
710                if let Some(drop_behavior) = drop_behavior {
711                    write!(f, " {drop_behavior}")?;
712                }
713                Ok(())
714            }
715            AlterTableOperation::DropForeignKey {
716                name,
717                drop_behavior,
718            } => {
719                write!(f, "DROP FOREIGN KEY {name}")?;
720                if let Some(drop_behavior) = drop_behavior {
721                    write!(f, " {drop_behavior}")?;
722                }
723                Ok(())
724            }
725            AlterTableOperation::DropIndex { name } => write!(f, "DROP INDEX {name}"),
726            AlterTableOperation::DropColumn {
727                has_column_keyword,
728                column_names: column_name,
729                if_exists,
730                drop_behavior,
731            } => {
732                write!(
733                    f,
734                    "DROP {}{}{}",
735                    if *has_column_keyword { "COLUMN " } else { "" },
736                    if *if_exists { "IF EXISTS " } else { "" },
737                    display_comma_separated(column_name),
738                )?;
739                if let Some(drop_behavior) = drop_behavior {
740                    write!(f, " {drop_behavior}")?;
741                }
742                Ok(())
743            }
744            AlterTableOperation::AttachPartition { partition } => {
745                write!(f, "ATTACH {partition}")
746            }
747            AlterTableOperation::DetachPartition { partition } => {
748                write!(f, "DETACH {partition}")
749            }
750            AlterTableOperation::EnableAlwaysRule { name } => {
751                write!(f, "ENABLE ALWAYS RULE {name}")
752            }
753            AlterTableOperation::EnableAlwaysTrigger { name } => {
754                write!(f, "ENABLE ALWAYS TRIGGER {name}")
755            }
756            AlterTableOperation::EnableReplicaRule { name } => {
757                write!(f, "ENABLE REPLICA RULE {name}")
758            }
759            AlterTableOperation::EnableReplicaTrigger { name } => {
760                write!(f, "ENABLE REPLICA TRIGGER {name}")
761            }
762            AlterTableOperation::EnableRowLevelSecurity => {
763                write!(f, "ENABLE ROW LEVEL SECURITY")
764            }
765            AlterTableOperation::EnableRule { name } => {
766                write!(f, "ENABLE RULE {name}")
767            }
768            AlterTableOperation::EnableTrigger { name } => {
769                write!(f, "ENABLE TRIGGER {name}")
770            }
771            AlterTableOperation::RenamePartitions {
772                old_partitions,
773                new_partitions,
774            } => write!(
775                f,
776                "PARTITION ({}) RENAME TO PARTITION ({})",
777                display_comma_separated(old_partitions),
778                display_comma_separated(new_partitions)
779            ),
780            AlterTableOperation::RenameColumn {
781                old_column_name,
782                new_column_name,
783            } => write!(f, "RENAME COLUMN {old_column_name} TO {new_column_name}"),
784            AlterTableOperation::RenameTable { table_name } => {
785                write!(f, "RENAME {table_name}")
786            }
787            AlterTableOperation::ChangeColumn {
788                old_name,
789                new_name,
790                data_type,
791                options,
792                column_position,
793            } => {
794                write!(f, "CHANGE COLUMN {old_name} {new_name} {data_type}")?;
795                if !options.is_empty() {
796                    write!(f, " {}", display_separated(options, " "))?;
797                }
798                if let Some(position) = column_position {
799                    write!(f, " {position}")?;
800                }
801
802                Ok(())
803            }
804            AlterTableOperation::ModifyColumn {
805                col_name,
806                data_type,
807                options,
808                column_position,
809            } => {
810                write!(f, "MODIFY COLUMN {col_name} {data_type}")?;
811                if !options.is_empty() {
812                    write!(f, " {}", display_separated(options, " "))?;
813                }
814                if let Some(position) = column_position {
815                    write!(f, " {position}")?;
816                }
817
818                Ok(())
819            }
820            AlterTableOperation::RenameConstraint { old_name, new_name } => {
821                write!(f, "RENAME CONSTRAINT {old_name} TO {new_name}")
822            }
823            AlterTableOperation::SwapWith { table_name } => {
824                write!(f, "SWAP WITH {table_name}")
825            }
826            AlterTableOperation::OwnerTo { new_owner } => {
827                write!(f, "OWNER TO {new_owner}")
828            }
829            AlterTableOperation::SetTblProperties { table_properties } => {
830                write!(
831                    f,
832                    "SET TBLPROPERTIES({})",
833                    display_comma_separated(table_properties)
834                )
835            }
836            AlterTableOperation::FreezePartition {
837                partition,
838                with_name,
839            } => {
840                write!(f, "FREEZE {partition}")?;
841                if let Some(name) = with_name {
842                    write!(f, " WITH NAME {name}")?;
843                }
844                Ok(())
845            }
846            AlterTableOperation::UnfreezePartition {
847                partition,
848                with_name,
849            } => {
850                write!(f, "UNFREEZE {partition}")?;
851                if let Some(name) = with_name {
852                    write!(f, " WITH NAME {name}")?;
853                }
854                Ok(())
855            }
856            AlterTableOperation::ClusterBy { exprs } => {
857                write!(f, "CLUSTER BY ({})", display_comma_separated(exprs))?;
858                Ok(())
859            }
860            AlterTableOperation::DropClusteringKey => {
861                write!(f, "DROP CLUSTERING KEY")?;
862                Ok(())
863            }
864            AlterTableOperation::SuspendRecluster => {
865                write!(f, "SUSPEND RECLUSTER")?;
866                Ok(())
867            }
868            AlterTableOperation::ResumeRecluster => {
869                write!(f, "RESUME RECLUSTER")?;
870                Ok(())
871            }
872            AlterTableOperation::Refresh { subpath } => {
873                write!(f, "REFRESH")?;
874                if let Some(path) = subpath {
875                    write!(f, " '{path}'")?;
876                }
877                Ok(())
878            }
879            AlterTableOperation::Suspend => {
880                write!(f, "SUSPEND")
881            }
882            AlterTableOperation::Resume => {
883                write!(f, "RESUME")
884            }
885            AlterTableOperation::AutoIncrement { equals, value } => {
886                write!(
887                    f,
888                    "AUTO_INCREMENT {}{}",
889                    if *equals { "= " } else { "" },
890                    value
891                )
892            }
893            AlterTableOperation::Lock { equals, lock } => {
894                write!(f, "LOCK {}{}", if *equals { "= " } else { "" }, lock)
895            }
896            AlterTableOperation::ReplicaIdentity { identity } => {
897                write!(f, "REPLICA IDENTITY {identity}")
898            }
899            AlterTableOperation::ValidateConstraint { name } => {
900                write!(f, "VALIDATE CONSTRAINT {name}")
901            }
902            AlterTableOperation::SetOptionsParens { options } => {
903                write!(f, "SET ({})", display_comma_separated(options))
904            }
905        }
906    }
907}
908
909impl fmt::Display for AlterIndexOperation {
910    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
911        match self {
912            AlterIndexOperation::RenameIndex { index_name } => {
913                write!(f, "RENAME TO {index_name}")
914            }
915        }
916    }
917}
918
919/// An `ALTER TYPE` statement (`Statement::AlterType`)
920#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
921#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
922#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
923pub struct AlterType {
924    pub name: ObjectName,
925    pub operation: AlterTypeOperation,
926}
927
928/// An [AlterType] operation
929#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
930#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
931#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
932pub enum AlterTypeOperation {
933    Rename(AlterTypeRename),
934    AddValue(AlterTypeAddValue),
935    RenameValue(AlterTypeRenameValue),
936}
937
938/// See [AlterTypeOperation::Rename]
939#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
940#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
941#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
942pub struct AlterTypeRename {
943    pub new_name: Ident,
944}
945
946/// See [AlterTypeOperation::AddValue]
947#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
948#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
949#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
950pub struct AlterTypeAddValue {
951    pub if_not_exists: bool,
952    pub value: Ident,
953    pub position: Option<AlterTypeAddValuePosition>,
954}
955
956/// See [AlterTypeAddValue]
957#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
958#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
959#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
960pub enum AlterTypeAddValuePosition {
961    Before(Ident),
962    After(Ident),
963}
964
965/// See [AlterTypeOperation::RenameValue]
966#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
967#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
968#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
969pub struct AlterTypeRenameValue {
970    pub from: Ident,
971    pub to: Ident,
972}
973
974impl fmt::Display for AlterTypeOperation {
975    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
976        match self {
977            Self::Rename(AlterTypeRename { new_name }) => {
978                write!(f, "RENAME TO {new_name}")
979            }
980            Self::AddValue(AlterTypeAddValue {
981                if_not_exists,
982                value,
983                position,
984            }) => {
985                write!(f, "ADD VALUE")?;
986                if *if_not_exists {
987                    write!(f, " IF NOT EXISTS")?;
988                }
989                write!(f, " {value}")?;
990                match position {
991                    Some(AlterTypeAddValuePosition::Before(neighbor_value)) => {
992                        write!(f, " BEFORE {neighbor_value}")?;
993                    }
994                    Some(AlterTypeAddValuePosition::After(neighbor_value)) => {
995                        write!(f, " AFTER {neighbor_value}")?;
996                    }
997                    None => {}
998                };
999                Ok(())
1000            }
1001            Self::RenameValue(AlterTypeRenameValue { from, to }) => {
1002                write!(f, "RENAME VALUE {from} TO {to}")
1003            }
1004        }
1005    }
1006}
1007
1008/// `ALTER OPERATOR` statement
1009/// See <https://www.postgresql.org/docs/current/sql-alteroperator.html>
1010#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1011#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1012#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1013pub struct AlterOperator {
1014    /// Operator name (can be schema-qualified)
1015    pub name: ObjectName,
1016    /// Left operand type (`None` if no left operand)
1017    pub left_type: Option<DataType>,
1018    /// Right operand type
1019    pub right_type: DataType,
1020    /// The operation to perform
1021    pub operation: AlterOperatorOperation,
1022}
1023
1024/// An [AlterOperator] operation
1025#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1026#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1027#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1028pub enum AlterOperatorOperation {
1029    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
1030    OwnerTo(Owner),
1031    /// `SET SCHEMA new_schema`
1032    SetSchema { schema_name: ObjectName },
1033    /// `SET ( options )`
1034    Set {
1035        /// List of operator options to set
1036        options: Vec<OperatorOption>,
1037    },
1038}
1039
1040/// Option for `ALTER OPERATOR SET` operation
1041#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1042#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1043#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1044pub enum OperatorOption {
1045    /// `RESTRICT = { res_proc | NONE }`
1046    Restrict(Option<ObjectName>),
1047    /// `JOIN = { join_proc | NONE }`
1048    Join(Option<ObjectName>),
1049    /// `COMMUTATOR = com_op`
1050    Commutator(ObjectName),
1051    /// `NEGATOR = neg_op`
1052    Negator(ObjectName),
1053    /// `HASHES`
1054    Hashes,
1055    /// `MERGES`
1056    Merges,
1057}
1058
1059impl fmt::Display for AlterOperator {
1060    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1061        write!(f, "ALTER OPERATOR {} (", self.name)?;
1062        if let Some(left_type) = &self.left_type {
1063            write!(f, "{}", left_type)?;
1064        } else {
1065            write!(f, "NONE")?;
1066        }
1067        write!(f, ", {}) {}", self.right_type, self.operation)
1068    }
1069}
1070
1071impl fmt::Display for AlterOperatorOperation {
1072    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1073        match self {
1074            Self::OwnerTo(owner) => write!(f, "OWNER TO {}", owner),
1075            Self::SetSchema { schema_name } => write!(f, "SET SCHEMA {}", schema_name),
1076            Self::Set { options } => {
1077                write!(f, "SET (")?;
1078                for (i, option) in options.iter().enumerate() {
1079                    if i > 0 {
1080                        write!(f, ", ")?;
1081                    }
1082                    write!(f, "{}", option)?;
1083                }
1084                write!(f, ")")
1085            }
1086        }
1087    }
1088}
1089
1090impl fmt::Display for OperatorOption {
1091    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1092        match self {
1093            Self::Restrict(Some(proc_name)) => write!(f, "RESTRICT = {}", proc_name),
1094            Self::Restrict(None) => write!(f, "RESTRICT = NONE"),
1095            Self::Join(Some(proc_name)) => write!(f, "JOIN = {}", proc_name),
1096            Self::Join(None) => write!(f, "JOIN = NONE"),
1097            Self::Commutator(op_name) => write!(f, "COMMUTATOR = {}", op_name),
1098            Self::Negator(op_name) => write!(f, "NEGATOR = {}", op_name),
1099            Self::Hashes => write!(f, "HASHES"),
1100            Self::Merges => write!(f, "MERGES"),
1101        }
1102    }
1103}
1104
1105/// An `ALTER COLUMN` (`Statement::AlterTable`) operation
1106#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1107#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1108#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1109pub enum AlterColumnOperation {
1110    /// `SET NOT NULL`
1111    SetNotNull,
1112    /// `DROP NOT NULL`
1113    DropNotNull,
1114    /// `SET DEFAULT <expr>`
1115    SetDefault { value: Expr },
1116    /// `DROP DEFAULT`
1117    DropDefault,
1118    /// `[SET DATA] TYPE <data_type> [USING <expr>]`
1119    SetDataType {
1120        data_type: DataType,
1121        /// PostgreSQL specific
1122        using: Option<Expr>,
1123        /// Set to true if the statement includes the `SET DATA TYPE` keywords
1124        had_set: bool,
1125    },
1126
1127    /// `ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]`
1128    ///
1129    /// Note: this is a PostgreSQL-specific operation.
1130    AddGenerated {
1131        generated_as: Option<GeneratedAs>,
1132        sequence_options: Option<Vec<SequenceOptions>>,
1133    },
1134}
1135
1136impl fmt::Display for AlterColumnOperation {
1137    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1138        match self {
1139            AlterColumnOperation::SetNotNull => write!(f, "SET NOT NULL",),
1140            AlterColumnOperation::DropNotNull => write!(f, "DROP NOT NULL",),
1141            AlterColumnOperation::SetDefault { value } => {
1142                write!(f, "SET DEFAULT {value}")
1143            }
1144            AlterColumnOperation::DropDefault => {
1145                write!(f, "DROP DEFAULT")
1146            }
1147            AlterColumnOperation::SetDataType {
1148                data_type,
1149                using,
1150                had_set,
1151            } => {
1152                if *had_set {
1153                    write!(f, "SET DATA ")?;
1154                }
1155                write!(f, "TYPE {data_type}")?;
1156                if let Some(expr) = using {
1157                    write!(f, " USING {expr}")?;
1158                }
1159                Ok(())
1160            }
1161            AlterColumnOperation::AddGenerated {
1162                generated_as,
1163                sequence_options,
1164            } => {
1165                let generated_as = match generated_as {
1166                    Some(GeneratedAs::Always) => " ALWAYS",
1167                    Some(GeneratedAs::ByDefault) => " BY DEFAULT",
1168                    _ => "",
1169                };
1170
1171                write!(f, "ADD GENERATED{generated_as} AS IDENTITY",)?;
1172                if let Some(options) = sequence_options {
1173                    write!(f, " (")?;
1174
1175                    for sequence_option in options {
1176                        write!(f, "{sequence_option}")?;
1177                    }
1178
1179                    write!(f, " )")?;
1180                }
1181                Ok(())
1182            }
1183        }
1184    }
1185}
1186
1187/// Representation whether a definition can can contains the KEY or INDEX keywords with the same
1188/// meaning.
1189///
1190/// This enum initially is directed to `FULLTEXT`,`SPATIAL`, and `UNIQUE` indexes on create table
1191/// statements of `MySQL` [(1)].
1192///
1193/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1194#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1195#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1196#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1197pub enum KeyOrIndexDisplay {
1198    /// Nothing to display
1199    None,
1200    /// Display the KEY keyword
1201    Key,
1202    /// Display the INDEX keyword
1203    Index,
1204}
1205
1206impl KeyOrIndexDisplay {
1207    pub fn is_none(self) -> bool {
1208        matches!(self, Self::None)
1209    }
1210}
1211
1212impl fmt::Display for KeyOrIndexDisplay {
1213    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1214        let left_space = matches!(f.align(), Some(fmt::Alignment::Right));
1215
1216        if left_space && !self.is_none() {
1217            f.write_char(' ')?
1218        }
1219
1220        match self {
1221            KeyOrIndexDisplay::None => {
1222                write!(f, "")
1223            }
1224            KeyOrIndexDisplay::Key => {
1225                write!(f, "KEY")
1226            }
1227            KeyOrIndexDisplay::Index => {
1228                write!(f, "INDEX")
1229            }
1230        }
1231    }
1232}
1233
1234/// Indexing method used by that index.
1235///
1236/// This structure isn't present on ANSI, but is found at least in [`MySQL` CREATE TABLE][1],
1237/// [`MySQL` CREATE INDEX][2], and [Postgresql CREATE INDEX][3] statements.
1238///
1239/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1240/// [2]: https://dev.mysql.com/doc/refman/8.0/en/create-index.html
1241/// [3]: https://www.postgresql.org/docs/14/sql-createindex.html
1242#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1243#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1244#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1245pub enum IndexType {
1246    BTree,
1247    Hash,
1248    GIN,
1249    GiST,
1250    SPGiST,
1251    BRIN,
1252    Bloom,
1253    /// Users may define their own index types, which would
1254    /// not be covered by the above variants.
1255    Custom(Ident),
1256}
1257
1258impl fmt::Display for IndexType {
1259    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1260        match self {
1261            Self::BTree => write!(f, "BTREE"),
1262            Self::Hash => write!(f, "HASH"),
1263            Self::GIN => write!(f, "GIN"),
1264            Self::GiST => write!(f, "GIST"),
1265            Self::SPGiST => write!(f, "SPGIST"),
1266            Self::BRIN => write!(f, "BRIN"),
1267            Self::Bloom => write!(f, "BLOOM"),
1268            Self::Custom(name) => write!(f, "{name}"),
1269        }
1270    }
1271}
1272
1273/// MySQL index option, used in [`CREATE TABLE`], [`CREATE INDEX`], and [`ALTER TABLE`].
1274///
1275/// [`CREATE TABLE`]: https://dev.mysql.com/doc/refman/8.4/en/create-table.html
1276/// [`CREATE INDEX`]: https://dev.mysql.com/doc/refman/8.4/en/create-index.html
1277/// [`ALTER TABLE`]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
1278#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1279#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1280#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1281pub enum IndexOption {
1282    /// `USING { BTREE | HASH }`: Index type to use for the index.
1283    ///
1284    /// Note that we permissively parse non-MySQL index types, like `GIN`.
1285    Using(IndexType),
1286    /// `COMMENT 'string'`: Specifies a comment for the index.
1287    Comment(String),
1288}
1289
1290impl fmt::Display for IndexOption {
1291    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1292        match self {
1293            Self::Using(index_type) => write!(f, "USING {index_type}"),
1294            Self::Comment(s) => write!(f, "COMMENT '{s}'"),
1295        }
1296    }
1297}
1298
1299/// [PostgreSQL] unique index nulls handling option: `[ NULLS [ NOT ] DISTINCT ]`
1300///
1301/// [PostgreSQL]: https://www.postgresql.org/docs/17/sql-altertable.html
1302#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1303#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1304#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1305pub enum NullsDistinctOption {
1306    /// Not specified
1307    None,
1308    /// NULLS DISTINCT
1309    Distinct,
1310    /// NULLS NOT DISTINCT
1311    NotDistinct,
1312}
1313
1314impl fmt::Display for NullsDistinctOption {
1315    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1316        match self {
1317            Self::None => Ok(()),
1318            Self::Distinct => write!(f, " NULLS DISTINCT"),
1319            Self::NotDistinct => write!(f, " NULLS NOT DISTINCT"),
1320        }
1321    }
1322}
1323
1324#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1325#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1326#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1327pub struct ProcedureParam {
1328    pub name: Ident,
1329    pub data_type: DataType,
1330    pub mode: Option<ArgMode>,
1331    pub default: Option<Expr>,
1332}
1333
1334impl fmt::Display for ProcedureParam {
1335    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1336        if let Some(mode) = &self.mode {
1337            if let Some(default) = &self.default {
1338                write!(f, "{mode} {} {} = {}", self.name, self.data_type, default)
1339            } else {
1340                write!(f, "{mode} {} {}", self.name, self.data_type)
1341            }
1342        } else if let Some(default) = &self.default {
1343            write!(f, "{} {} = {}", self.name, self.data_type, default)
1344        } else {
1345            write!(f, "{} {}", self.name, self.data_type)
1346        }
1347    }
1348}
1349
1350/// SQL column definition
1351#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1352#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1353#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1354pub struct ColumnDef {
1355    pub name: Ident,
1356    pub data_type: DataType,
1357    pub options: Vec<ColumnOptionDef>,
1358}
1359
1360impl fmt::Display for ColumnDef {
1361    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1362        if self.data_type == DataType::Unspecified {
1363            write!(f, "{}", self.name)?;
1364        } else {
1365            write!(f, "{} {}", self.name, self.data_type)?;
1366        }
1367        for option in &self.options {
1368            write!(f, " {option}")?;
1369        }
1370        Ok(())
1371    }
1372}
1373
1374/// Column definition specified in a `CREATE VIEW` statement.
1375///
1376/// Syntax
1377/// ```markdown
1378/// <name> [data_type][OPTIONS(option, ...)]
1379///
1380/// option: <name> = <value>
1381/// ```
1382///
1383/// Examples:
1384/// ```sql
1385/// name
1386/// age OPTIONS(description = "age column", tag = "prod")
1387/// amount COMMENT 'The total amount for the order line'
1388/// created_at DateTime64
1389/// ```
1390#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1391#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1392#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1393pub struct ViewColumnDef {
1394    pub name: Ident,
1395    pub data_type: Option<DataType>,
1396    pub options: Option<ColumnOptions>,
1397}
1398
1399#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1400#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1401#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1402pub enum ColumnOptions {
1403    CommaSeparated(Vec<ColumnOption>),
1404    SpaceSeparated(Vec<ColumnOption>),
1405}
1406
1407impl ColumnOptions {
1408    pub fn as_slice(&self) -> &[ColumnOption] {
1409        match self {
1410            ColumnOptions::CommaSeparated(options) => options.as_slice(),
1411            ColumnOptions::SpaceSeparated(options) => options.as_slice(),
1412        }
1413    }
1414}
1415
1416impl fmt::Display for ViewColumnDef {
1417    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1418        write!(f, "{}", self.name)?;
1419        if let Some(data_type) = self.data_type.as_ref() {
1420            write!(f, " {data_type}")?;
1421        }
1422        if let Some(options) = self.options.as_ref() {
1423            match options {
1424                ColumnOptions::CommaSeparated(column_options) => {
1425                    write!(f, " {}", display_comma_separated(column_options.as_slice()))?;
1426                }
1427                ColumnOptions::SpaceSeparated(column_options) => {
1428                    write!(f, " {}", display_separated(column_options.as_slice(), " "))?
1429                }
1430            }
1431        }
1432        Ok(())
1433    }
1434}
1435
1436/// An optionally-named `ColumnOption`: `[ CONSTRAINT <name> ] <column-option>`.
1437///
1438/// Note that implementations are substantially more permissive than the ANSI
1439/// specification on what order column options can be presented in, and whether
1440/// they are allowed to be named. The specification distinguishes between
1441/// constraints (NOT NULL, UNIQUE, PRIMARY KEY, and CHECK), which can be named
1442/// and can appear in any order, and other options (DEFAULT, GENERATED), which
1443/// cannot be named and must appear in a fixed order. `PostgreSQL`, however,
1444/// allows preceding any option with `CONSTRAINT <name>`, even those that are
1445/// not really constraints, like NULL and DEFAULT. MSSQL is less permissive,
1446/// allowing DEFAULT, UNIQUE, PRIMARY KEY and CHECK to be named, but not NULL or
1447/// NOT NULL constraints (the last of which is in violation of the spec).
1448///
1449/// For maximum flexibility, we don't distinguish between constraint and
1450/// non-constraint options, lumping them all together under the umbrella of
1451/// "column options," and we allow any column option to be named.
1452#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1453#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1454#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1455pub struct ColumnOptionDef {
1456    pub name: Option<Ident>,
1457    pub option: ColumnOption,
1458}
1459
1460impl fmt::Display for ColumnOptionDef {
1461    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1462        write!(f, "{}{}", display_constraint_name(&self.name), self.option)
1463    }
1464}
1465
1466/// Identity is a column option for defining an identity or autoincrement column in a `CREATE TABLE` statement.
1467/// Syntax
1468/// ```sql
1469/// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1470/// ```
1471/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1472/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1473#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1474#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1475#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1476pub enum IdentityPropertyKind {
1477    /// An identity property declared via the `AUTOINCREMENT` key word
1478    /// Example:
1479    /// ```sql
1480    ///  AUTOINCREMENT(100, 1) NOORDER
1481    ///  AUTOINCREMENT START 100 INCREMENT 1 ORDER
1482    /// ```
1483    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1484    Autoincrement(IdentityProperty),
1485    /// An identity property declared via the `IDENTITY` key word
1486    /// Example, [MS SQL Server] or [Snowflake]:
1487    /// ```sql
1488    ///  IDENTITY(100, 1)
1489    /// ```
1490    /// [Snowflake]
1491    /// ```sql
1492    ///  IDENTITY(100, 1) ORDER
1493    ///  IDENTITY START 100 INCREMENT 1 NOORDER
1494    /// ```
1495    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1496    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1497    Identity(IdentityProperty),
1498}
1499
1500impl fmt::Display for IdentityPropertyKind {
1501    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1502        let (command, property) = match self {
1503            IdentityPropertyKind::Identity(property) => ("IDENTITY", property),
1504            IdentityPropertyKind::Autoincrement(property) => ("AUTOINCREMENT", property),
1505        };
1506        write!(f, "{command}")?;
1507        if let Some(parameters) = &property.parameters {
1508            write!(f, "{parameters}")?;
1509        }
1510        if let Some(order) = &property.order {
1511            write!(f, "{order}")?;
1512        }
1513        Ok(())
1514    }
1515}
1516
1517#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1518#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1519#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1520pub struct IdentityProperty {
1521    pub parameters: Option<IdentityPropertyFormatKind>,
1522    pub order: Option<IdentityPropertyOrder>,
1523}
1524
1525/// A format of parameters of identity column.
1526///
1527/// It is [Snowflake] specific.
1528/// Syntax
1529/// ```sql
1530/// (seed , increment) | START num INCREMENT num
1531/// ```
1532/// [MS SQL Server] uses one way of representing these parameters.
1533/// Syntax
1534/// ```sql
1535/// (seed , increment)
1536/// ```
1537/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1538/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1539#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1540#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1541#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1542pub enum IdentityPropertyFormatKind {
1543    /// A parameters of identity column declared like parameters of function call
1544    /// Example:
1545    /// ```sql
1546    ///  (100, 1)
1547    /// ```
1548    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1549    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1550    FunctionCall(IdentityParameters),
1551    /// A parameters of identity column declared with keywords `START` and `INCREMENT`
1552    /// Example:
1553    /// ```sql
1554    ///  START 100 INCREMENT 1
1555    /// ```
1556    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1557    StartAndIncrement(IdentityParameters),
1558}
1559
1560impl fmt::Display for IdentityPropertyFormatKind {
1561    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1562        match self {
1563            IdentityPropertyFormatKind::FunctionCall(parameters) => {
1564                write!(f, "({}, {})", parameters.seed, parameters.increment)
1565            }
1566            IdentityPropertyFormatKind::StartAndIncrement(parameters) => {
1567                write!(
1568                    f,
1569                    " START {} INCREMENT {}",
1570                    parameters.seed, parameters.increment
1571                )
1572            }
1573        }
1574    }
1575}
1576#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1577#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1578#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1579pub struct IdentityParameters {
1580    pub seed: Expr,
1581    pub increment: Expr,
1582}
1583
1584/// The identity column option specifies how values are generated for the auto-incremented column, either in increasing or decreasing order.
1585/// Syntax
1586/// ```sql
1587/// ORDER | NOORDER
1588/// ```
1589/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1590#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1591#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1592#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1593pub enum IdentityPropertyOrder {
1594    Order,
1595    NoOrder,
1596}
1597
1598impl fmt::Display for IdentityPropertyOrder {
1599    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1600        match self {
1601            IdentityPropertyOrder::Order => write!(f, " ORDER"),
1602            IdentityPropertyOrder::NoOrder => write!(f, " NOORDER"),
1603        }
1604    }
1605}
1606
1607/// Column policy that identify a security policy of access to a column.
1608/// Syntax
1609/// ```sql
1610/// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1611/// [ WITH ] PROJECTION POLICY <policy_name>
1612/// ```
1613/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1614#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1615#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1616#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1617pub enum ColumnPolicy {
1618    MaskingPolicy(ColumnPolicyProperty),
1619    ProjectionPolicy(ColumnPolicyProperty),
1620}
1621
1622impl fmt::Display for ColumnPolicy {
1623    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1624        let (command, property) = match self {
1625            ColumnPolicy::MaskingPolicy(property) => ("MASKING POLICY", property),
1626            ColumnPolicy::ProjectionPolicy(property) => ("PROJECTION POLICY", property),
1627        };
1628        if property.with {
1629            write!(f, "WITH ")?;
1630        }
1631        write!(f, "{command} {}", property.policy_name)?;
1632        if let Some(using_columns) = &property.using_columns {
1633            write!(f, " USING ({})", display_comma_separated(using_columns))?;
1634        }
1635        Ok(())
1636    }
1637}
1638
1639#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1640#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1641#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1642pub struct ColumnPolicyProperty {
1643    /// This flag indicates that the column policy option is declared using the `WITH` prefix.
1644    /// Example
1645    /// ```sql
1646    /// WITH PROJECTION POLICY sample_policy
1647    /// ```
1648    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1649    pub with: bool,
1650    pub policy_name: ObjectName,
1651    pub using_columns: Option<Vec<Ident>>,
1652}
1653
1654/// Tags option of column
1655/// Syntax
1656/// ```sql
1657/// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1658/// ```
1659/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1660#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1661#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1662#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1663pub struct TagsColumnOption {
1664    /// This flag indicates that the tags option is declared using the `WITH` prefix.
1665    /// Example:
1666    /// ```sql
1667    /// WITH TAG (A = 'Tag A')
1668    /// ```
1669    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1670    pub with: bool,
1671    pub tags: Vec<Tag>,
1672}
1673
1674impl fmt::Display for TagsColumnOption {
1675    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1676        if self.with {
1677            write!(f, "WITH ")?;
1678        }
1679        write!(f, "TAG ({})", display_comma_separated(&self.tags))?;
1680        Ok(())
1681    }
1682}
1683
1684/// `ColumnOption`s are modifiers that follow a column definition in a `CREATE
1685/// TABLE` statement.
1686#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1687#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1688#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1689pub enum ColumnOption {
1690    /// `NULL`
1691    Null,
1692    /// `NOT NULL`
1693    NotNull,
1694    /// `DEFAULT <restricted-expr>`
1695    Default(Expr),
1696
1697    /// `MATERIALIZE <expr>`
1698    /// Syntax: `b INT MATERIALIZE (a + 1)`
1699    ///
1700    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1701    Materialized(Expr),
1702    /// `EPHEMERAL [<expr>]`
1703    ///
1704    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1705    Ephemeral(Option<Expr>),
1706    /// `ALIAS <expr>`
1707    ///
1708    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1709    Alias(Expr),
1710
1711    /// `PRIMARY KEY [<constraint_characteristics>]`
1712    PrimaryKey(PrimaryKeyConstraint),
1713    /// `UNIQUE [<constraint_characteristics>]`
1714    Unique(UniqueConstraint),
1715    /// A referential integrity constraint (`REFERENCES <foreign_table> (<referred_columns>)
1716    /// [ MATCH { FULL | PARTIAL | SIMPLE } ]
1717    /// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
1718    ///   [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
1719    /// }         
1720    /// [<constraint_characteristics>]
1721    /// `).
1722    ForeignKey(ForeignKeyConstraint),
1723    /// `CHECK (<expr>)`
1724    Check(CheckConstraint),
1725    /// Dialect-specific options, such as:
1726    /// - MySQL's `AUTO_INCREMENT` or SQLite's `AUTOINCREMENT`
1727    /// - ...
1728    DialectSpecific(Vec<Token>),
1729    CharacterSet(ObjectName),
1730    Collation(ObjectName),
1731    Comment(String),
1732    OnUpdate(Expr),
1733    /// `Generated`s are modifiers that follow a column definition in a `CREATE
1734    /// TABLE` statement.
1735    Generated {
1736        generated_as: GeneratedAs,
1737        sequence_options: Option<Vec<SequenceOptions>>,
1738        generation_expr: Option<Expr>,
1739        generation_expr_mode: Option<GeneratedExpressionMode>,
1740        /// false if 'GENERATED ALWAYS' is skipped (option starts with AS)
1741        generated_keyword: bool,
1742    },
1743    /// BigQuery specific: Explicit column options in a view [1] or table [2]
1744    /// Syntax
1745    /// ```sql
1746    /// OPTIONS(description="field desc")
1747    /// ```
1748    /// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#view_column_option_list
1749    /// [2]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#column_option_list
1750    Options(Vec<SqlOption>),
1751    /// Creates an identity or an autoincrement column in a table.
1752    /// Syntax
1753    /// ```sql
1754    /// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1755    /// ```
1756    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1757    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1758    Identity(IdentityPropertyKind),
1759    /// SQLite specific: ON CONFLICT option on column definition
1760    /// <https://www.sqlite.org/lang_conflict.html>
1761    OnConflict(Keyword),
1762    /// Snowflake specific: an option of specifying security masking or projection policy to set on a column.
1763    /// Syntax:
1764    /// ```sql
1765    /// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1766    /// [ WITH ] PROJECTION POLICY <policy_name>
1767    /// ```
1768    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1769    Policy(ColumnPolicy),
1770    /// Snowflake specific: Specifies the tag name and the tag string value.
1771    /// Syntax:
1772    /// ```sql
1773    /// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1774    /// ```
1775    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1776    Tags(TagsColumnOption),
1777    /// MySQL specific: Spatial reference identifier
1778    /// Syntax:
1779    /// ```sql
1780    /// CREATE TABLE geom (g GEOMETRY NOT NULL SRID 4326);
1781    /// ```
1782    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/creating-spatial-indexes.html
1783    Srid(Box<Expr>),
1784    /// MySQL specific: Column is invisible via SELECT *
1785    /// Syntax:
1786    /// ```sql
1787    /// CREATE TABLE t (foo INT, bar INT INVISIBLE);
1788    /// ```
1789    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/invisible-columns.html
1790    Invisible,
1791}
1792
1793impl From<UniqueConstraint> for ColumnOption {
1794    fn from(c: UniqueConstraint) -> Self {
1795        ColumnOption::Unique(c)
1796    }
1797}
1798
1799impl From<PrimaryKeyConstraint> for ColumnOption {
1800    fn from(c: PrimaryKeyConstraint) -> Self {
1801        ColumnOption::PrimaryKey(c)
1802    }
1803}
1804
1805impl From<CheckConstraint> for ColumnOption {
1806    fn from(c: CheckConstraint) -> Self {
1807        ColumnOption::Check(c)
1808    }
1809}
1810impl From<ForeignKeyConstraint> for ColumnOption {
1811    fn from(fk: ForeignKeyConstraint) -> Self {
1812        ColumnOption::ForeignKey(fk)
1813    }
1814}
1815
1816impl fmt::Display for ColumnOption {
1817    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1818        use ColumnOption::*;
1819        match self {
1820            Null => write!(f, "NULL"),
1821            NotNull => write!(f, "NOT NULL"),
1822            Default(expr) => write!(f, "DEFAULT {expr}"),
1823            Materialized(expr) => write!(f, "MATERIALIZED {expr}"),
1824            Ephemeral(expr) => {
1825                if let Some(e) = expr {
1826                    write!(f, "EPHEMERAL {e}")
1827                } else {
1828                    write!(f, "EPHEMERAL")
1829                }
1830            }
1831            Alias(expr) => write!(f, "ALIAS {expr}"),
1832            PrimaryKey(constraint) => {
1833                write!(f, "PRIMARY KEY")?;
1834                if let Some(characteristics) = &constraint.characteristics {
1835                    write!(f, " {characteristics}")?;
1836                }
1837                Ok(())
1838            }
1839            Unique(constraint) => {
1840                write!(f, "UNIQUE")?;
1841                if let Some(characteristics) = &constraint.characteristics {
1842                    write!(f, " {characteristics}")?;
1843                }
1844                Ok(())
1845            }
1846            ForeignKey(constraint) => {
1847                write!(f, "REFERENCES {}", constraint.foreign_table)?;
1848                if !constraint.referred_columns.is_empty() {
1849                    write!(
1850                        f,
1851                        " ({})",
1852                        display_comma_separated(&constraint.referred_columns)
1853                    )?;
1854                }
1855                if let Some(match_kind) = &constraint.match_kind {
1856                    write!(f, " {match_kind}")?;
1857                }
1858                if let Some(action) = &constraint.on_delete {
1859                    write!(f, " ON DELETE {action}")?;
1860                }
1861                if let Some(action) = &constraint.on_update {
1862                    write!(f, " ON UPDATE {action}")?;
1863                }
1864                if let Some(characteristics) = &constraint.characteristics {
1865                    write!(f, " {characteristics}")?;
1866                }
1867                Ok(())
1868            }
1869            Check(constraint) => write!(f, "{constraint}"),
1870            DialectSpecific(val) => write!(f, "{}", display_separated(val, " ")),
1871            CharacterSet(n) => write!(f, "CHARACTER SET {n}"),
1872            Collation(n) => write!(f, "COLLATE {n}"),
1873            Comment(v) => write!(f, "COMMENT '{}'", escape_single_quote_string(v)),
1874            OnUpdate(expr) => write!(f, "ON UPDATE {expr}"),
1875            Generated {
1876                generated_as,
1877                sequence_options,
1878                generation_expr,
1879                generation_expr_mode,
1880                generated_keyword,
1881            } => {
1882                if let Some(expr) = generation_expr {
1883                    let modifier = match generation_expr_mode {
1884                        None => "",
1885                        Some(GeneratedExpressionMode::Virtual) => " VIRTUAL",
1886                        Some(GeneratedExpressionMode::Stored) => " STORED",
1887                    };
1888                    if *generated_keyword {
1889                        write!(f, "GENERATED ALWAYS AS ({expr}){modifier}")?;
1890                    } else {
1891                        write!(f, "AS ({expr}){modifier}")?;
1892                    }
1893                    Ok(())
1894                } else {
1895                    // Like Postgres - generated from sequence
1896                    let when = match generated_as {
1897                        GeneratedAs::Always => "ALWAYS",
1898                        GeneratedAs::ByDefault => "BY DEFAULT",
1899                        // ExpStored goes with an expression, handled above
1900                        GeneratedAs::ExpStored => "",
1901                    };
1902                    write!(f, "GENERATED {when} AS IDENTITY")?;
1903                    if sequence_options.is_some() {
1904                        let so = sequence_options.as_ref().unwrap();
1905                        if !so.is_empty() {
1906                            write!(f, " (")?;
1907                        }
1908                        for sequence_option in so {
1909                            write!(f, "{sequence_option}")?;
1910                        }
1911                        if !so.is_empty() {
1912                            write!(f, " )")?;
1913                        }
1914                    }
1915                    Ok(())
1916                }
1917            }
1918            Options(options) => {
1919                write!(f, "OPTIONS({})", display_comma_separated(options))
1920            }
1921            Identity(parameters) => {
1922                write!(f, "{parameters}")
1923            }
1924            OnConflict(keyword) => {
1925                write!(f, "ON CONFLICT {keyword:?}")?;
1926                Ok(())
1927            }
1928            Policy(parameters) => {
1929                write!(f, "{parameters}")
1930            }
1931            Tags(tags) => {
1932                write!(f, "{tags}")
1933            }
1934            Srid(srid) => {
1935                write!(f, "SRID {srid}")
1936            }
1937            Invisible => {
1938                write!(f, "INVISIBLE")
1939            }
1940        }
1941    }
1942}
1943
1944/// `GeneratedAs`s are modifiers that follow a column option in a `generated`.
1945/// 'ExpStored' is used for a column generated from an expression and stored.
1946#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1947#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1948#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1949pub enum GeneratedAs {
1950    Always,
1951    ByDefault,
1952    ExpStored,
1953}
1954
1955/// `GeneratedExpressionMode`s are modifiers that follow an expression in a `generated`.
1956/// No modifier is typically the same as Virtual.
1957#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1958#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1959#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1960pub enum GeneratedExpressionMode {
1961    Virtual,
1962    Stored,
1963}
1964
1965#[must_use]
1966pub(crate) fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
1967    struct ConstraintName<'a>(&'a Option<Ident>);
1968    impl fmt::Display for ConstraintName<'_> {
1969        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1970            if let Some(name) = self.0 {
1971                write!(f, "CONSTRAINT {name} ")?;
1972            }
1973            Ok(())
1974        }
1975    }
1976    ConstraintName(name)
1977}
1978
1979/// If `option` is
1980/// * `Some(inner)` => create display struct for `"{prefix}{inner}{postfix}"`
1981/// * `_` => do nothing
1982#[must_use]
1983pub(crate) fn display_option<'a, T: fmt::Display>(
1984    prefix: &'a str,
1985    postfix: &'a str,
1986    option: &'a Option<T>,
1987) -> impl fmt::Display + 'a {
1988    struct OptionDisplay<'a, T>(&'a str, &'a str, &'a Option<T>);
1989    impl<T: fmt::Display> fmt::Display for OptionDisplay<'_, T> {
1990        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1991            if let Some(inner) = self.2 {
1992                let (prefix, postfix) = (self.0, self.1);
1993                write!(f, "{prefix}{inner}{postfix}")?;
1994            }
1995            Ok(())
1996        }
1997    }
1998    OptionDisplay(prefix, postfix, option)
1999}
2000
2001/// If `option` is
2002/// * `Some(inner)` => create display struct for `" {inner}"`
2003/// * `_` => do nothing
2004#[must_use]
2005pub(crate) fn display_option_spaced<T: fmt::Display>(option: &Option<T>) -> impl fmt::Display + '_ {
2006    display_option(" ", "", option)
2007}
2008
2009/// `<constraint_characteristics> = [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ]`
2010///
2011/// Used in UNIQUE and foreign key constraints. The individual settings may occur in any order.
2012#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Default, Eq, Ord, Hash)]
2013#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2014#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2015pub struct ConstraintCharacteristics {
2016    /// `[ DEFERRABLE | NOT DEFERRABLE ]`
2017    pub deferrable: Option<bool>,
2018    /// `[ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]`
2019    pub initially: Option<DeferrableInitial>,
2020    /// `[ ENFORCED | NOT ENFORCED ]`
2021    pub enforced: Option<bool>,
2022}
2023
2024#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2025#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2026#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2027pub enum DeferrableInitial {
2028    /// `INITIALLY IMMEDIATE`
2029    Immediate,
2030    /// `INITIALLY DEFERRED`
2031    Deferred,
2032}
2033
2034impl ConstraintCharacteristics {
2035    fn deferrable_text(&self) -> Option<&'static str> {
2036        self.deferrable.map(|deferrable| {
2037            if deferrable {
2038                "DEFERRABLE"
2039            } else {
2040                "NOT DEFERRABLE"
2041            }
2042        })
2043    }
2044
2045    fn initially_immediate_text(&self) -> Option<&'static str> {
2046        self.initially
2047            .map(|initially_immediate| match initially_immediate {
2048                DeferrableInitial::Immediate => "INITIALLY IMMEDIATE",
2049                DeferrableInitial::Deferred => "INITIALLY DEFERRED",
2050            })
2051    }
2052
2053    fn enforced_text(&self) -> Option<&'static str> {
2054        self.enforced.map(
2055            |enforced| {
2056                if enforced {
2057                    "ENFORCED"
2058                } else {
2059                    "NOT ENFORCED"
2060                }
2061            },
2062        )
2063    }
2064}
2065
2066impl fmt::Display for ConstraintCharacteristics {
2067    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2068        let deferrable = self.deferrable_text();
2069        let initially_immediate = self.initially_immediate_text();
2070        let enforced = self.enforced_text();
2071
2072        match (deferrable, initially_immediate, enforced) {
2073            (None, None, None) => Ok(()),
2074            (None, None, Some(enforced)) => write!(f, "{enforced}"),
2075            (None, Some(initial), None) => write!(f, "{initial}"),
2076            (None, Some(initial), Some(enforced)) => write!(f, "{initial} {enforced}"),
2077            (Some(deferrable), None, None) => write!(f, "{deferrable}"),
2078            (Some(deferrable), None, Some(enforced)) => write!(f, "{deferrable} {enforced}"),
2079            (Some(deferrable), Some(initial), None) => write!(f, "{deferrable} {initial}"),
2080            (Some(deferrable), Some(initial), Some(enforced)) => {
2081                write!(f, "{deferrable} {initial} {enforced}")
2082            }
2083        }
2084    }
2085}
2086
2087/// `<referential_action> =
2088/// { RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT }`
2089///
2090/// Used in foreign key constraints in `ON UPDATE` and `ON DELETE` options.
2091#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2092#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2093#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2094pub enum ReferentialAction {
2095    Restrict,
2096    Cascade,
2097    SetNull,
2098    NoAction,
2099    SetDefault,
2100}
2101
2102impl fmt::Display for ReferentialAction {
2103    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2104        f.write_str(match self {
2105            ReferentialAction::Restrict => "RESTRICT",
2106            ReferentialAction::Cascade => "CASCADE",
2107            ReferentialAction::SetNull => "SET NULL",
2108            ReferentialAction::NoAction => "NO ACTION",
2109            ReferentialAction::SetDefault => "SET DEFAULT",
2110        })
2111    }
2112}
2113
2114/// `<drop behavior> ::= CASCADE | RESTRICT`.
2115///
2116/// Used in `DROP` statements.
2117#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2118#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2119#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2120pub enum DropBehavior {
2121    Restrict,
2122    Cascade,
2123}
2124
2125impl fmt::Display for DropBehavior {
2126    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2127        f.write_str(match self {
2128            DropBehavior::Restrict => "RESTRICT",
2129            DropBehavior::Cascade => "CASCADE",
2130        })
2131    }
2132}
2133
2134/// SQL user defined type definition
2135#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2136#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2137#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2138pub enum UserDefinedTypeRepresentation {
2139    /// Composite type: `CREATE TYPE name AS (attributes)`
2140    Composite {
2141        attributes: Vec<UserDefinedTypeCompositeAttributeDef>,
2142    },
2143    /// Enum type: `CREATE TYPE name AS ENUM (labels)`
2144    ///
2145    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2146    Enum { labels: Vec<Ident> },
2147    /// Range type: `CREATE TYPE name AS RANGE (options)`
2148    ///
2149    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2150    Range {
2151        options: Vec<UserDefinedTypeRangeOption>,
2152    },
2153    /// Base type (SQL definition): `CREATE TYPE name (options)`
2154    ///
2155    /// Note the lack of `AS` keyword
2156    ///
2157    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2158    SqlDefinition {
2159        options: Vec<UserDefinedTypeSqlDefinitionOption>,
2160    },
2161}
2162
2163impl fmt::Display for UserDefinedTypeRepresentation {
2164    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2165        match self {
2166            Self::Composite { attributes } => {
2167                write!(f, "AS ({})", display_comma_separated(attributes))
2168            }
2169            Self::Enum { labels } => {
2170                write!(f, "AS ENUM ({})", display_comma_separated(labels))
2171            }
2172            Self::Range { options } => {
2173                write!(f, "AS RANGE ({})", display_comma_separated(options))
2174            }
2175            Self::SqlDefinition { options } => {
2176                write!(f, "({})", display_comma_separated(options))
2177            }
2178        }
2179    }
2180}
2181
2182/// SQL user defined type attribute definition
2183#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2184#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2185#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2186pub struct UserDefinedTypeCompositeAttributeDef {
2187    pub name: Ident,
2188    pub data_type: DataType,
2189    pub collation: Option<ObjectName>,
2190}
2191
2192impl fmt::Display for UserDefinedTypeCompositeAttributeDef {
2193    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2194        write!(f, "{} {}", self.name, self.data_type)?;
2195        if let Some(collation) = &self.collation {
2196            write!(f, " COLLATE {collation}")?;
2197        }
2198        Ok(())
2199    }
2200}
2201
2202/// Internal length specification for PostgreSQL user-defined base types.
2203///
2204/// Specifies the internal length in bytes of the new type's internal representation.
2205/// The default assumption is that it is variable-length.
2206///
2207/// # PostgreSQL Documentation
2208/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2209///
2210/// # Examples
2211/// ```sql
2212/// CREATE TYPE mytype (
2213///     INPUT = in_func,
2214///     OUTPUT = out_func,
2215///     INTERNALLENGTH = 16  -- Fixed 16-byte length
2216/// );
2217///
2218/// CREATE TYPE mytype2 (
2219///     INPUT = in_func,
2220///     OUTPUT = out_func,
2221///     INTERNALLENGTH = VARIABLE  -- Variable length
2222/// );
2223/// ```
2224#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2225#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2226#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2227pub enum UserDefinedTypeInternalLength {
2228    /// Fixed internal length: `INTERNALLENGTH = <number>`
2229    Fixed(u64),
2230    /// Variable internal length: `INTERNALLENGTH = VARIABLE`
2231    Variable,
2232}
2233
2234impl fmt::Display for UserDefinedTypeInternalLength {
2235    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2236        match self {
2237            UserDefinedTypeInternalLength::Fixed(n) => write!(f, "{}", n),
2238            UserDefinedTypeInternalLength::Variable => write!(f, "VARIABLE"),
2239        }
2240    }
2241}
2242
2243/// Alignment specification for PostgreSQL user-defined base types.
2244///
2245/// Specifies the storage alignment requirement for values of the data type.
2246/// The allowed values equate to alignment on 1, 2, 4, or 8 byte boundaries.
2247/// Note that variable-length types must have an alignment of at least 4, since
2248/// they necessarily contain an int4 as their first component.
2249///
2250/// # PostgreSQL Documentation
2251/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2252///
2253/// # Examples
2254/// ```sql
2255/// CREATE TYPE mytype (
2256///     INPUT = in_func,
2257///     OUTPUT = out_func,
2258///     ALIGNMENT = int4  -- 4-byte alignment
2259/// );
2260/// ```
2261#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2262#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2263#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2264pub enum Alignment {
2265    /// Single-byte alignment: `ALIGNMENT = char`
2266    Char,
2267    /// 2-byte alignment: `ALIGNMENT = int2`
2268    Int2,
2269    /// 4-byte alignment: `ALIGNMENT = int4`
2270    Int4,
2271    /// 8-byte alignment: `ALIGNMENT = double`
2272    Double,
2273}
2274
2275impl fmt::Display for Alignment {
2276    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2277        match self {
2278            Alignment::Char => write!(f, "char"),
2279            Alignment::Int2 => write!(f, "int2"),
2280            Alignment::Int4 => write!(f, "int4"),
2281            Alignment::Double => write!(f, "double"),
2282        }
2283    }
2284}
2285
2286/// Storage specification for PostgreSQL user-defined base types.
2287///
2288/// Specifies the storage strategy for values of the data type:
2289/// - `plain`: Prevents compression and out-of-line storage (for fixed-length types)
2290/// - `external`: Allows out-of-line storage but not compression
2291/// - `extended`: Allows both compression and out-of-line storage (default for most types)
2292/// - `main`: Allows compression but discourages out-of-line storage
2293///
2294/// # PostgreSQL Documentation
2295/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2296///
2297/// # Examples
2298/// ```sql
2299/// CREATE TYPE mytype (
2300///     INPUT = in_func,
2301///     OUTPUT = out_func,
2302///     STORAGE = plain
2303/// );
2304/// ```
2305#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2306#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2307#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2308pub enum UserDefinedTypeStorage {
2309    /// No compression or out-of-line storage: `STORAGE = plain`
2310    Plain,
2311    /// Out-of-line storage allowed, no compression: `STORAGE = external`
2312    External,
2313    /// Both compression and out-of-line storage allowed: `STORAGE = extended`
2314    Extended,
2315    /// Compression allowed, out-of-line discouraged: `STORAGE = main`
2316    Main,
2317}
2318
2319impl fmt::Display for UserDefinedTypeStorage {
2320    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2321        match self {
2322            UserDefinedTypeStorage::Plain => write!(f, "plain"),
2323            UserDefinedTypeStorage::External => write!(f, "external"),
2324            UserDefinedTypeStorage::Extended => write!(f, "extended"),
2325            UserDefinedTypeStorage::Main => write!(f, "main"),
2326        }
2327    }
2328}
2329
2330/// Options for PostgreSQL `CREATE TYPE ... AS RANGE` statement.
2331///
2332/// Range types are data types representing a range of values of some element type
2333/// (called the range's subtype). These options configure the behavior of the range type.
2334///
2335/// # PostgreSQL Documentation
2336/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2337///
2338/// # Examples
2339/// ```sql
2340/// CREATE TYPE int4range AS RANGE (
2341///     SUBTYPE = int4,
2342///     SUBTYPE_OPCLASS = int4_ops,
2343///     CANONICAL = int4range_canonical,
2344///     SUBTYPE_DIFF = int4range_subdiff
2345/// );
2346/// ```
2347#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2348#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2349#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2350pub enum UserDefinedTypeRangeOption {
2351    /// The element type that the range type will represent: `SUBTYPE = subtype`
2352    Subtype(DataType),
2353    /// The operator class for the subtype: `SUBTYPE_OPCLASS = subtype_operator_class`
2354    SubtypeOpClass(ObjectName),
2355    /// Collation to use for ordering the subtype: `COLLATION = collation`
2356    Collation(ObjectName),
2357    /// Function to convert range values to canonical form: `CANONICAL = canonical_function`
2358    Canonical(ObjectName),
2359    /// Function to compute the difference between two subtype values: `SUBTYPE_DIFF = subtype_diff_function`
2360    SubtypeDiff(ObjectName),
2361    /// Name of the corresponding multirange type: `MULTIRANGE_TYPE_NAME = multirange_type_name`
2362    MultirangeTypeName(ObjectName),
2363}
2364
2365impl fmt::Display for UserDefinedTypeRangeOption {
2366    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2367        match self {
2368            UserDefinedTypeRangeOption::Subtype(dt) => write!(f, "SUBTYPE = {}", dt),
2369            UserDefinedTypeRangeOption::SubtypeOpClass(name) => {
2370                write!(f, "SUBTYPE_OPCLASS = {}", name)
2371            }
2372            UserDefinedTypeRangeOption::Collation(name) => write!(f, "COLLATION = {}", name),
2373            UserDefinedTypeRangeOption::Canonical(name) => write!(f, "CANONICAL = {}", name),
2374            UserDefinedTypeRangeOption::SubtypeDiff(name) => write!(f, "SUBTYPE_DIFF = {}", name),
2375            UserDefinedTypeRangeOption::MultirangeTypeName(name) => {
2376                write!(f, "MULTIRANGE_TYPE_NAME = {}", name)
2377            }
2378        }
2379    }
2380}
2381
2382/// Options for PostgreSQL `CREATE TYPE ... (<options>)` statement (base type definition).
2383///
2384/// Base types are the lowest-level data types in PostgreSQL. To define a new base type,
2385/// you must specify functions that convert it to and from text representation, and optionally
2386/// binary representation and other properties.
2387///
2388/// Note: This syntax uses parentheses directly after the type name, without the `AS` keyword.
2389///
2390/// # PostgreSQL Documentation
2391/// See: <https://www.postgresql.org/docs/current/sql-createtype.html>
2392///
2393/// # Examples
2394/// ```sql
2395/// CREATE TYPE complex (
2396///     INPUT = complex_in,
2397///     OUTPUT = complex_out,
2398///     INTERNALLENGTH = 16,
2399///     ALIGNMENT = double
2400/// );
2401/// ```
2402#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2403#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2404#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2405pub enum UserDefinedTypeSqlDefinitionOption {
2406    /// Function to convert from external text representation to internal: `INPUT = input_function`
2407    Input(ObjectName),
2408    /// Function to convert from internal to external text representation: `OUTPUT = output_function`
2409    Output(ObjectName),
2410    /// Function to convert from external binary representation to internal: `RECEIVE = receive_function`
2411    Receive(ObjectName),
2412    /// Function to convert from internal to external binary representation: `SEND = send_function`
2413    Send(ObjectName),
2414    /// Function to convert type modifiers from text array to internal form: `TYPMOD_IN = type_modifier_input_function`
2415    TypmodIn(ObjectName),
2416    /// Function to convert type modifiers from internal to text form: `TYPMOD_OUT = type_modifier_output_function`
2417    TypmodOut(ObjectName),
2418    /// Function to compute statistics for the data type: `ANALYZE = analyze_function`
2419    Analyze(ObjectName),
2420    /// Function to handle subscripting operations: `SUBSCRIPT = subscript_function`
2421    Subscript(ObjectName),
2422    /// Internal storage size in bytes, or VARIABLE for variable-length: `INTERNALLENGTH = { internallength | VARIABLE }`
2423    InternalLength(UserDefinedTypeInternalLength),
2424    /// Indicates values are passed by value rather than by reference: `PASSEDBYVALUE`
2425    PassedByValue,
2426    /// Storage alignment requirement (1, 2, 4, or 8 bytes): `ALIGNMENT = alignment`
2427    Alignment(Alignment),
2428    /// Storage strategy for varlena types: `STORAGE = storage`
2429    Storage(UserDefinedTypeStorage),
2430    /// Copy properties from an existing type: `LIKE = like_type`
2431    Like(ObjectName),
2432    /// Type category for implicit casting rules (single char): `CATEGORY = category`
2433    Category(char),
2434    /// Whether this type is preferred within its category: `PREFERRED = preferred`
2435    Preferred(bool),
2436    /// Default value for the type: `DEFAULT = default`
2437    Default(Expr),
2438    /// Element type for array types: `ELEMENT = element`
2439    Element(DataType),
2440    /// Delimiter character for array value display: `DELIMITER = delimiter`
2441    Delimiter(String),
2442    /// Whether the type supports collation: `COLLATABLE = collatable`
2443    Collatable(bool),
2444}
2445
2446impl fmt::Display for UserDefinedTypeSqlDefinitionOption {
2447    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2448        match self {
2449            UserDefinedTypeSqlDefinitionOption::Input(name) => write!(f, "INPUT = {}", name),
2450            UserDefinedTypeSqlDefinitionOption::Output(name) => write!(f, "OUTPUT = {}", name),
2451            UserDefinedTypeSqlDefinitionOption::Receive(name) => write!(f, "RECEIVE = {}", name),
2452            UserDefinedTypeSqlDefinitionOption::Send(name) => write!(f, "SEND = {}", name),
2453            UserDefinedTypeSqlDefinitionOption::TypmodIn(name) => write!(f, "TYPMOD_IN = {}", name),
2454            UserDefinedTypeSqlDefinitionOption::TypmodOut(name) => {
2455                write!(f, "TYPMOD_OUT = {}", name)
2456            }
2457            UserDefinedTypeSqlDefinitionOption::Analyze(name) => write!(f, "ANALYZE = {}", name),
2458            UserDefinedTypeSqlDefinitionOption::Subscript(name) => {
2459                write!(f, "SUBSCRIPT = {}", name)
2460            }
2461            UserDefinedTypeSqlDefinitionOption::InternalLength(len) => {
2462                write!(f, "INTERNALLENGTH = {}", len)
2463            }
2464            UserDefinedTypeSqlDefinitionOption::PassedByValue => write!(f, "PASSEDBYVALUE"),
2465            UserDefinedTypeSqlDefinitionOption::Alignment(align) => {
2466                write!(f, "ALIGNMENT = {}", align)
2467            }
2468            UserDefinedTypeSqlDefinitionOption::Storage(storage) => {
2469                write!(f, "STORAGE = {}", storage)
2470            }
2471            UserDefinedTypeSqlDefinitionOption::Like(name) => write!(f, "LIKE = {}", name),
2472            UserDefinedTypeSqlDefinitionOption::Category(c) => write!(f, "CATEGORY = '{}'", c),
2473            UserDefinedTypeSqlDefinitionOption::Preferred(b) => write!(f, "PREFERRED = {}", b),
2474            UserDefinedTypeSqlDefinitionOption::Default(expr) => write!(f, "DEFAULT = {}", expr),
2475            UserDefinedTypeSqlDefinitionOption::Element(dt) => write!(f, "ELEMENT = {}", dt),
2476            UserDefinedTypeSqlDefinitionOption::Delimiter(s) => {
2477                write!(f, "DELIMITER = '{}'", escape_single_quote_string(s))
2478            }
2479            UserDefinedTypeSqlDefinitionOption::Collatable(b) => write!(f, "COLLATABLE = {}", b),
2480        }
2481    }
2482}
2483
2484/// PARTITION statement used in ALTER TABLE et al. such as in Hive and ClickHouse SQL.
2485/// For example, ClickHouse's OPTIMIZE TABLE supports syntax like PARTITION ID 'partition_id' and PARTITION expr.
2486/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2487#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2488#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2489#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2490pub enum Partition {
2491    Identifier(Ident),
2492    Expr(Expr),
2493    /// ClickHouse supports PART expr which represents physical partition in disk.
2494    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
2495    Part(Expr),
2496    Partitions(Vec<Expr>),
2497}
2498
2499impl fmt::Display for Partition {
2500    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2501        match self {
2502            Partition::Identifier(id) => write!(f, "PARTITION ID {id}"),
2503            Partition::Expr(expr) => write!(f, "PARTITION {expr}"),
2504            Partition::Part(expr) => write!(f, "PART {expr}"),
2505            Partition::Partitions(partitions) => {
2506                write!(f, "PARTITION ({})", display_comma_separated(partitions))
2507            }
2508        }
2509    }
2510}
2511
2512/// DEDUPLICATE statement used in OPTIMIZE TABLE et al. such as in ClickHouse SQL
2513/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2514#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2515#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2516#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2517pub enum Deduplicate {
2518    All,
2519    ByExpression(Expr),
2520}
2521
2522impl fmt::Display for Deduplicate {
2523    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2524        match self {
2525            Deduplicate::All => write!(f, "DEDUPLICATE"),
2526            Deduplicate::ByExpression(expr) => write!(f, "DEDUPLICATE BY {expr}"),
2527        }
2528    }
2529}
2530
2531/// Hive supports `CLUSTERED BY` statement in `CREATE TABLE`.
2532/// Syntax: `CLUSTERED BY (col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS`
2533///
2534/// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2535#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2536#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2537#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2538pub struct ClusteredBy {
2539    pub columns: Vec<Ident>,
2540    pub sorted_by: Option<Vec<OrderByExpr>>,
2541    pub num_buckets: Value,
2542}
2543
2544impl fmt::Display for ClusteredBy {
2545    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2546        write!(
2547            f,
2548            "CLUSTERED BY ({})",
2549            display_comma_separated(&self.columns)
2550        )?;
2551        if let Some(ref sorted_by) = self.sorted_by {
2552            write!(f, " SORTED BY ({})", display_comma_separated(sorted_by))?;
2553        }
2554        write!(f, " INTO {} BUCKETS", self.num_buckets)
2555    }
2556}
2557
2558/// CREATE INDEX statement.
2559#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2560#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2561#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2562pub struct CreateIndex {
2563    /// index name
2564    pub name: Option<ObjectName>,
2565    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2566    pub table_name: ObjectName,
2567    /// Index type used in the statement. Can also be found inside [`CreateIndex::index_options`]
2568    /// depending on the position of the option within the statement.
2569    pub using: Option<IndexType>,
2570    pub columns: Vec<IndexColumn>,
2571    pub unique: bool,
2572    pub concurrently: bool,
2573    pub if_not_exists: bool,
2574    pub include: Vec<Ident>,
2575    pub nulls_distinct: Option<bool>,
2576    /// WITH clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
2577    pub with: Vec<Expr>,
2578    pub predicate: Option<Expr>,
2579    pub index_options: Vec<IndexOption>,
2580    /// [MySQL] allows a subset of options normally used for `ALTER TABLE`:
2581    ///
2582    /// - `ALGORITHM`
2583    /// - `LOCK`
2584    ///
2585    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/create-index.html
2586    pub alter_options: Vec<AlterTableOperation>,
2587}
2588
2589impl fmt::Display for CreateIndex {
2590    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2591        write!(
2592            f,
2593            "CREATE {unique}INDEX {concurrently}{if_not_exists}",
2594            unique = if self.unique { "UNIQUE " } else { "" },
2595            concurrently = if self.concurrently {
2596                "CONCURRENTLY "
2597            } else {
2598                ""
2599            },
2600            if_not_exists = if self.if_not_exists {
2601                "IF NOT EXISTS "
2602            } else {
2603                ""
2604            },
2605        )?;
2606        if let Some(value) = &self.name {
2607            write!(f, "{value} ")?;
2608        }
2609        write!(f, "ON {}", self.table_name)?;
2610        if let Some(value) = &self.using {
2611            write!(f, " USING {value} ")?;
2612        }
2613        write!(f, "({})", display_comma_separated(&self.columns))?;
2614        if !self.include.is_empty() {
2615            write!(f, " INCLUDE ({})", display_comma_separated(&self.include))?;
2616        }
2617        if let Some(value) = self.nulls_distinct {
2618            if value {
2619                write!(f, " NULLS DISTINCT")?;
2620            } else {
2621                write!(f, " NULLS NOT DISTINCT")?;
2622            }
2623        }
2624        if !self.with.is_empty() {
2625            write!(f, " WITH ({})", display_comma_separated(&self.with))?;
2626        }
2627        if let Some(predicate) = &self.predicate {
2628            write!(f, " WHERE {predicate}")?;
2629        }
2630        if !self.index_options.is_empty() {
2631            write!(f, " {}", display_separated(&self.index_options, " "))?;
2632        }
2633        if !self.alter_options.is_empty() {
2634            write!(f, " {}", display_separated(&self.alter_options, " "))?;
2635        }
2636        Ok(())
2637    }
2638}
2639
2640/// CREATE TABLE statement.
2641#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2642#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2643#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2644pub struct CreateTable {
2645    pub or_replace: bool,
2646    pub temporary: bool,
2647    pub external: bool,
2648    pub dynamic: bool,
2649    pub global: Option<bool>,
2650    pub if_not_exists: bool,
2651    pub transient: bool,
2652    pub volatile: bool,
2653    pub iceberg: bool,
2654    /// Table name
2655    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2656    pub name: ObjectName,
2657    /// Optional schema
2658    pub columns: Vec<ColumnDef>,
2659    pub constraints: Vec<TableConstraint>,
2660    pub hive_distribution: HiveDistributionStyle,
2661    pub hive_formats: Option<HiveFormat>,
2662    pub table_options: CreateTableOptions,
2663    pub file_format: Option<FileFormat>,
2664    pub location: Option<String>,
2665    pub query: Option<Box<Query>>,
2666    pub without_rowid: bool,
2667    pub like: Option<CreateTableLikeKind>,
2668    pub clone: Option<ObjectName>,
2669    pub version: Option<TableVersion>,
2670    // For Hive dialect, the table comment is after the column definitions without `=`,
2671    // so the `comment` field is optional and different than the comment field in the general options list.
2672    // [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2673    pub comment: Option<CommentDef>,
2674    pub on_commit: Option<OnCommit>,
2675    /// ClickHouse "ON CLUSTER" clause:
2676    /// <https://clickhouse.com/docs/en/sql-reference/distributed-ddl/>
2677    pub on_cluster: Option<Ident>,
2678    /// ClickHouse "PRIMARY KEY " clause.
2679    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
2680    pub primary_key: Option<Box<Expr>>,
2681    /// ClickHouse "ORDER BY " clause. Note that omitted ORDER BY is different
2682    /// than empty (represented as ()), the latter meaning "no sorting".
2683    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
2684    pub order_by: Option<OneOrManyWithParens<Expr>>,
2685    /// BigQuery: A partition expression for the table.
2686    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#partition_expression>
2687    pub partition_by: Option<Box<Expr>>,
2688    /// BigQuery: Table clustering column list.
2689    /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#table_option_list>
2690    /// Snowflake: Table clustering list which contains base column, expressions on base columns.
2691    /// <https://docs.snowflake.com/en/user-guide/tables-clustering-keys#defining-a-clustering-key-for-a-table>
2692    pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
2693    /// Hive: Table clustering column list.
2694    /// <https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable>
2695    pub clustered_by: Option<ClusteredBy>,
2696    /// Postgres `INHERITs` clause, which contains the list of tables from which
2697    /// the new table inherits.
2698    /// <https://www.postgresql.org/docs/current/ddl-inherit.html>
2699    /// <https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-INHERITS>
2700    pub inherits: Option<Vec<ObjectName>>,
2701    /// PostgreSQL `PARTITION OF` clause to create a partition of a parent table.
2702    /// Contains the parent table name.
2703    /// <https://www.postgresql.org/docs/current/sql-createtable.html>
2704    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
2705    pub partition_of: Option<ObjectName>,
2706    /// PostgreSQL partition bound specification for PARTITION OF.
2707    /// <https://www.postgresql.org/docs/current/sql-createtable.html>
2708    pub for_values: Option<ForValues>,
2709    /// SQLite "STRICT" clause.
2710    /// if the "STRICT" table-option keyword is added to the end, after the closing ")",
2711    /// then strict typing rules apply to that table.
2712    pub strict: bool,
2713    /// Snowflake "COPY GRANTS" clause
2714    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2715    pub copy_grants: bool,
2716    /// Snowflake "ENABLE_SCHEMA_EVOLUTION" clause
2717    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2718    pub enable_schema_evolution: Option<bool>,
2719    /// Snowflake "CHANGE_TRACKING" clause
2720    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2721    pub change_tracking: Option<bool>,
2722    /// Snowflake "DATA_RETENTION_TIME_IN_DAYS" clause
2723    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2724    pub data_retention_time_in_days: Option<u64>,
2725    /// Snowflake "MAX_DATA_EXTENSION_TIME_IN_DAYS" clause
2726    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2727    pub max_data_extension_time_in_days: Option<u64>,
2728    /// Snowflake "DEFAULT_DDL_COLLATION" clause
2729    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2730    pub default_ddl_collation: Option<String>,
2731    /// Snowflake "WITH AGGREGATION POLICY" clause
2732    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2733    pub with_aggregation_policy: Option<ObjectName>,
2734    /// Snowflake "WITH ROW ACCESS POLICY" clause
2735    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2736    pub with_row_access_policy: Option<RowAccessPolicy>,
2737    /// Snowflake "WITH TAG" clause
2738    /// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
2739    pub with_tags: Option<Vec<Tag>>,
2740    /// Snowflake "EXTERNAL_VOLUME" clause for Iceberg tables
2741    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2742    pub external_volume: Option<String>,
2743    /// Snowflake "BASE_LOCATION" clause for Iceberg tables
2744    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2745    pub base_location: Option<String>,
2746    /// Snowflake "CATALOG" clause for Iceberg tables
2747    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2748    pub catalog: Option<String>,
2749    /// Snowflake "CATALOG_SYNC" clause for Iceberg tables
2750    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2751    pub catalog_sync: Option<String>,
2752    /// Snowflake "STORAGE_SERIALIZATION_POLICY" clause for Iceberg tables
2753    /// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
2754    pub storage_serialization_policy: Option<StorageSerializationPolicy>,
2755    /// Snowflake "TARGET_LAG" clause for dybamic tables
2756    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2757    pub target_lag: Option<String>,
2758    /// Snowflake "WAREHOUSE" clause for dybamic tables
2759    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2760    pub warehouse: Option<Ident>,
2761    /// Snowflake "REFRESH_MODE" clause for dybamic tables
2762    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2763    pub refresh_mode: Option<RefreshModeKind>,
2764    /// Snowflake "INITIALIZE" clause for dybamic tables
2765    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2766    pub initialize: Option<InitializeKind>,
2767    /// Snowflake "REQUIRE USER" clause for dybamic tables
2768    /// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
2769    pub require_user: bool,
2770}
2771
2772impl fmt::Display for CreateTable {
2773    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2774        // We want to allow the following options
2775        // Empty column list, allowed by PostgreSQL:
2776        //   `CREATE TABLE t ()`
2777        // No columns provided for CREATE TABLE AS:
2778        //   `CREATE TABLE t AS SELECT a from t2`
2779        // Columns provided for CREATE TABLE AS:
2780        //   `CREATE TABLE t (a INT) AS SELECT a from t2`
2781        write!(
2782            f,
2783            "CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}{dynamic}{iceberg}TABLE {if_not_exists}{name}",
2784            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
2785            external = if self.external { "EXTERNAL " } else { "" },
2786            global = self.global
2787                .map(|global| {
2788                    if global {
2789                        "GLOBAL "
2790                    } else {
2791                        "LOCAL "
2792                    }
2793                })
2794                .unwrap_or(""),
2795            if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
2796            temporary = if self.temporary { "TEMPORARY " } else { "" },
2797            transient = if self.transient { "TRANSIENT " } else { "" },
2798            volatile = if self.volatile { "VOLATILE " } else { "" },
2799            // Only for Snowflake
2800            iceberg = if self.iceberg { "ICEBERG " } else { "" },
2801            dynamic = if self.dynamic { "DYNAMIC " } else { "" },
2802            name = self.name,
2803        )?;
2804        if let Some(partition_of) = &self.partition_of {
2805            write!(f, " PARTITION OF {partition_of}")?;
2806        }
2807        if let Some(on_cluster) = &self.on_cluster {
2808            write!(f, " ON CLUSTER {on_cluster}")?;
2809        }
2810        if !self.columns.is_empty() || !self.constraints.is_empty() {
2811            f.write_str(" (")?;
2812            NewLine.fmt(f)?;
2813            Indent(DisplayCommaSeparated(&self.columns)).fmt(f)?;
2814            if !self.columns.is_empty() && !self.constraints.is_empty() {
2815                f.write_str(",")?;
2816                SpaceOrNewline.fmt(f)?;
2817            }
2818            Indent(DisplayCommaSeparated(&self.constraints)).fmt(f)?;
2819            NewLine.fmt(f)?;
2820            f.write_str(")")?;
2821        } else if self.query.is_none()
2822            && self.like.is_none()
2823            && self.clone.is_none()
2824            && self.partition_of.is_none()
2825        {
2826            // PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
2827            f.write_str(" ()")?;
2828        } else if let Some(CreateTableLikeKind::Parenthesized(like_in_columns_list)) = &self.like {
2829            write!(f, " ({like_in_columns_list})")?;
2830        }
2831        if let Some(for_values) = &self.for_values {
2832            write!(f, " {for_values}")?;
2833        }
2834
2835        // Hive table comment should be after column definitions, please refer to:
2836        // [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2837        if let Some(comment) = &self.comment {
2838            write!(f, " COMMENT '{comment}'")?;
2839        }
2840
2841        // Only for SQLite
2842        if self.without_rowid {
2843            write!(f, " WITHOUT ROWID")?;
2844        }
2845
2846        if let Some(CreateTableLikeKind::Plain(like)) = &self.like {
2847            write!(f, " {like}")?;
2848        }
2849
2850        if let Some(c) = &self.clone {
2851            write!(f, " CLONE {c}")?;
2852        }
2853
2854        if let Some(version) = &self.version {
2855            write!(f, " {version}")?;
2856        }
2857
2858        match &self.hive_distribution {
2859            HiveDistributionStyle::PARTITIONED { columns } => {
2860                write!(f, " PARTITIONED BY ({})", display_comma_separated(columns))?;
2861            }
2862            HiveDistributionStyle::SKEWED {
2863                columns,
2864                on,
2865                stored_as_directories,
2866            } => {
2867                write!(
2868                    f,
2869                    " SKEWED BY ({})) ON ({})",
2870                    display_comma_separated(columns),
2871                    display_comma_separated(on)
2872                )?;
2873                if *stored_as_directories {
2874                    write!(f, " STORED AS DIRECTORIES")?;
2875                }
2876            }
2877            _ => (),
2878        }
2879
2880        if let Some(clustered_by) = &self.clustered_by {
2881            write!(f, " {clustered_by}")?;
2882        }
2883
2884        if let Some(HiveFormat {
2885            row_format,
2886            serde_properties,
2887            storage,
2888            location,
2889        }) = &self.hive_formats
2890        {
2891            match row_format {
2892                Some(HiveRowFormat::SERDE { class }) => write!(f, " ROW FORMAT SERDE '{class}'")?,
2893                Some(HiveRowFormat::DELIMITED { delimiters }) => {
2894                    write!(f, " ROW FORMAT DELIMITED")?;
2895                    if !delimiters.is_empty() {
2896                        write!(f, " {}", display_separated(delimiters, " "))?;
2897                    }
2898                }
2899                None => (),
2900            }
2901            match storage {
2902                Some(HiveIOFormat::IOF {
2903                    input_format,
2904                    output_format,
2905                }) => write!(
2906                    f,
2907                    " STORED AS INPUTFORMAT {input_format} OUTPUTFORMAT {output_format}"
2908                )?,
2909                Some(HiveIOFormat::FileFormat { format }) if !self.external => {
2910                    write!(f, " STORED AS {format}")?
2911                }
2912                _ => (),
2913            }
2914            if let Some(serde_properties) = serde_properties.as_ref() {
2915                write!(
2916                    f,
2917                    " WITH SERDEPROPERTIES ({})",
2918                    display_comma_separated(serde_properties)
2919                )?;
2920            }
2921            if !self.external {
2922                if let Some(loc) = location {
2923                    write!(f, " LOCATION '{loc}'")?;
2924                }
2925            }
2926        }
2927        if self.external {
2928            if let Some(file_format) = self.file_format {
2929                write!(f, " STORED AS {file_format}")?;
2930            }
2931            if let Some(location) = &self.location {
2932                write!(f, " LOCATION '{location}'")?;
2933            }
2934        }
2935
2936        match &self.table_options {
2937            options @ CreateTableOptions::With(_)
2938            | options @ CreateTableOptions::Plain(_)
2939            | options @ CreateTableOptions::TableProperties(_) => write!(f, " {options}")?,
2940            _ => (),
2941        }
2942
2943        if let Some(primary_key) = &self.primary_key {
2944            write!(f, " PRIMARY KEY {primary_key}")?;
2945        }
2946        if let Some(order_by) = &self.order_by {
2947            write!(f, " ORDER BY {order_by}")?;
2948        }
2949        if let Some(inherits) = &self.inherits {
2950            write!(f, " INHERITS ({})", display_comma_separated(inherits))?;
2951        }
2952        if let Some(partition_by) = self.partition_by.as_ref() {
2953            write!(f, " PARTITION BY {partition_by}")?;
2954        }
2955        if let Some(cluster_by) = self.cluster_by.as_ref() {
2956            write!(f, " CLUSTER BY {cluster_by}")?;
2957        }
2958        if let options @ CreateTableOptions::Options(_) = &self.table_options {
2959            write!(f, " {options}")?;
2960        }
2961        if let Some(external_volume) = self.external_volume.as_ref() {
2962            write!(f, " EXTERNAL_VOLUME='{external_volume}'")?;
2963        }
2964
2965        if let Some(catalog) = self.catalog.as_ref() {
2966            write!(f, " CATALOG='{catalog}'")?;
2967        }
2968
2969        if self.iceberg {
2970            if let Some(base_location) = self.base_location.as_ref() {
2971                write!(f, " BASE_LOCATION='{base_location}'")?;
2972            }
2973        }
2974
2975        if let Some(catalog_sync) = self.catalog_sync.as_ref() {
2976            write!(f, " CATALOG_SYNC='{catalog_sync}'")?;
2977        }
2978
2979        if let Some(storage_serialization_policy) = self.storage_serialization_policy.as_ref() {
2980            write!(
2981                f,
2982                " STORAGE_SERIALIZATION_POLICY={storage_serialization_policy}"
2983            )?;
2984        }
2985
2986        if self.copy_grants {
2987            write!(f, " COPY GRANTS")?;
2988        }
2989
2990        if let Some(is_enabled) = self.enable_schema_evolution {
2991            write!(
2992                f,
2993                " ENABLE_SCHEMA_EVOLUTION={}",
2994                if is_enabled { "TRUE" } else { "FALSE" }
2995            )?;
2996        }
2997
2998        if let Some(is_enabled) = self.change_tracking {
2999            write!(
3000                f,
3001                " CHANGE_TRACKING={}",
3002                if is_enabled { "TRUE" } else { "FALSE" }
3003            )?;
3004        }
3005
3006        if let Some(data_retention_time_in_days) = self.data_retention_time_in_days {
3007            write!(
3008                f,
3009                " DATA_RETENTION_TIME_IN_DAYS={data_retention_time_in_days}",
3010            )?;
3011        }
3012
3013        if let Some(max_data_extension_time_in_days) = self.max_data_extension_time_in_days {
3014            write!(
3015                f,
3016                " MAX_DATA_EXTENSION_TIME_IN_DAYS={max_data_extension_time_in_days}",
3017            )?;
3018        }
3019
3020        if let Some(default_ddl_collation) = &self.default_ddl_collation {
3021            write!(f, " DEFAULT_DDL_COLLATION='{default_ddl_collation}'",)?;
3022        }
3023
3024        if let Some(with_aggregation_policy) = &self.with_aggregation_policy {
3025            write!(f, " WITH AGGREGATION POLICY {with_aggregation_policy}",)?;
3026        }
3027
3028        if let Some(row_access_policy) = &self.with_row_access_policy {
3029            write!(f, " {row_access_policy}",)?;
3030        }
3031
3032        if let Some(tag) = &self.with_tags {
3033            write!(f, " WITH TAG ({})", display_comma_separated(tag.as_slice()))?;
3034        }
3035
3036        if let Some(target_lag) = &self.target_lag {
3037            write!(f, " TARGET_LAG='{target_lag}'")?;
3038        }
3039
3040        if let Some(warehouse) = &self.warehouse {
3041            write!(f, " WAREHOUSE={warehouse}")?;
3042        }
3043
3044        if let Some(refresh_mode) = &self.refresh_mode {
3045            write!(f, " REFRESH_MODE={refresh_mode}")?;
3046        }
3047
3048        if let Some(initialize) = &self.initialize {
3049            write!(f, " INITIALIZE={initialize}")?;
3050        }
3051
3052        if self.require_user {
3053            write!(f, " REQUIRE USER")?;
3054        }
3055
3056        if self.on_commit.is_some() {
3057            let on_commit = match self.on_commit {
3058                Some(OnCommit::DeleteRows) => "ON COMMIT DELETE ROWS",
3059                Some(OnCommit::PreserveRows) => "ON COMMIT PRESERVE ROWS",
3060                Some(OnCommit::Drop) => "ON COMMIT DROP",
3061                None => "",
3062            };
3063            write!(f, " {on_commit}")?;
3064        }
3065        if self.strict {
3066            write!(f, " STRICT")?;
3067        }
3068        if let Some(query) = &self.query {
3069            write!(f, " AS {query}")?;
3070        }
3071        Ok(())
3072    }
3073}
3074
3075/// PostgreSQL partition bound specification for `PARTITION OF`.
3076///
3077/// Specifies partition bounds for a child partition table.
3078///
3079/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createtable.html)
3080#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3081#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3082#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3083pub enum ForValues {
3084    /// `FOR VALUES IN (expr, ...)`
3085    In(Vec<Expr>),
3086    /// `FOR VALUES FROM (expr|MINVALUE|MAXVALUE, ...) TO (expr|MINVALUE|MAXVALUE, ...)`
3087    From {
3088        from: Vec<PartitionBoundValue>,
3089        to: Vec<PartitionBoundValue>,
3090    },
3091    /// `FOR VALUES WITH (MODULUS n, REMAINDER r)`
3092    With { modulus: u64, remainder: u64 },
3093    /// `DEFAULT`
3094    Default,
3095}
3096
3097impl fmt::Display for ForValues {
3098    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3099        match self {
3100            ForValues::In(values) => {
3101                write!(f, "FOR VALUES IN ({})", display_comma_separated(values))
3102            }
3103            ForValues::From { from, to } => {
3104                write!(
3105                    f,
3106                    "FOR VALUES FROM ({}) TO ({})",
3107                    display_comma_separated(from),
3108                    display_comma_separated(to)
3109                )
3110            }
3111            ForValues::With { modulus, remainder } => {
3112                write!(
3113                    f,
3114                    "FOR VALUES WITH (MODULUS {modulus}, REMAINDER {remainder})"
3115                )
3116            }
3117            ForValues::Default => write!(f, "DEFAULT"),
3118        }
3119    }
3120}
3121
3122/// A value in a partition bound specification.
3123///
3124/// Used in RANGE partition bounds where values can be expressions,
3125/// MINVALUE (negative infinity), or MAXVALUE (positive infinity).
3126#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3127#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3128#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3129pub enum PartitionBoundValue {
3130    Expr(Expr),
3131    MinValue,
3132    MaxValue,
3133}
3134
3135impl fmt::Display for PartitionBoundValue {
3136    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3137        match self {
3138            PartitionBoundValue::Expr(expr) => write!(f, "{expr}"),
3139            PartitionBoundValue::MinValue => write!(f, "MINVALUE"),
3140            PartitionBoundValue::MaxValue => write!(f, "MAXVALUE"),
3141        }
3142    }
3143}
3144
3145#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3146#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3147#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3148/// ```sql
3149/// CREATE DOMAIN name [ AS ] data_type
3150///         [ COLLATE collation ]
3151///         [ DEFAULT expression ]
3152///         [ domain_constraint [ ... ] ]
3153///
3154///     where domain_constraint is:
3155///
3156///     [ CONSTRAINT constraint_name ]
3157///     { NOT NULL | NULL | CHECK (expression) }
3158/// ```
3159/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createdomain.html)
3160pub struct CreateDomain {
3161    /// The name of the domain to be created.
3162    pub name: ObjectName,
3163    /// The data type of the domain.
3164    pub data_type: DataType,
3165    /// The collation of the domain.
3166    pub collation: Option<Ident>,
3167    /// The default value of the domain.
3168    pub default: Option<Expr>,
3169    /// The constraints of the domain.
3170    pub constraints: Vec<TableConstraint>,
3171}
3172
3173impl fmt::Display for CreateDomain {
3174    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3175        write!(
3176            f,
3177            "CREATE DOMAIN {name} AS {data_type}",
3178            name = self.name,
3179            data_type = self.data_type
3180        )?;
3181        if let Some(collation) = &self.collation {
3182            write!(f, " COLLATE {collation}")?;
3183        }
3184        if let Some(default) = &self.default {
3185            write!(f, " DEFAULT {default}")?;
3186        }
3187        if !self.constraints.is_empty() {
3188            write!(f, " {}", display_separated(&self.constraints, " "))?;
3189        }
3190        Ok(())
3191    }
3192}
3193
3194#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3195#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3196#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3197pub struct CreateFunction {
3198    /// True if this is a `CREATE OR ALTER FUNCTION` statement
3199    ///
3200    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql?view=sql-server-ver16#or-alter)
3201    pub or_alter: bool,
3202    pub or_replace: bool,
3203    pub temporary: bool,
3204    pub if_not_exists: bool,
3205    pub name: ObjectName,
3206    pub args: Option<Vec<OperateFunctionArg>>,
3207    pub return_type: Option<DataType>,
3208    /// The expression that defines the function.
3209    ///
3210    /// Examples:
3211    /// ```sql
3212    /// AS ((SELECT 1))
3213    /// AS "console.log();"
3214    /// ```
3215    pub function_body: Option<CreateFunctionBody>,
3216    /// Behavior attribute for the function
3217    ///
3218    /// IMMUTABLE | STABLE | VOLATILE
3219    ///
3220    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3221    pub behavior: Option<FunctionBehavior>,
3222    /// CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
3223    ///
3224    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3225    pub called_on_null: Option<FunctionCalledOnNull>,
3226    /// PARALLEL { UNSAFE | RESTRICTED | SAFE }
3227    ///
3228    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3229    pub parallel: Option<FunctionParallel>,
3230    /// SECURITY { DEFINER | INVOKER }
3231    ///
3232    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3233    pub security: Option<FunctionSecurity>,
3234    /// SET configuration_parameter clauses
3235    ///
3236    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
3237    pub set_params: Vec<FunctionDefinitionSetParam>,
3238    /// USING ... (Hive only)
3239    pub using: Option<CreateFunctionUsing>,
3240    /// Language used in a UDF definition.
3241    ///
3242    /// Example:
3243    /// ```sql
3244    /// CREATE FUNCTION foo() LANGUAGE js AS "console.log();"
3245    /// ```
3246    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_javascript_udf)
3247    pub language: Option<Ident>,
3248    /// Determinism keyword used for non-sql UDF definitions.
3249    ///
3250    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
3251    pub determinism_specifier: Option<FunctionDeterminismSpecifier>,
3252    /// List of options for creating the function.
3253    ///
3254    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
3255    pub options: Option<Vec<SqlOption>>,
3256    /// Connection resource for a remote function.
3257    ///
3258    /// Example:
3259    /// ```sql
3260    /// CREATE FUNCTION foo()
3261    /// RETURNS FLOAT64
3262    /// REMOTE WITH CONNECTION us.myconnection
3263    /// ```
3264    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
3265    pub remote_connection: Option<ObjectName>,
3266}
3267
3268impl fmt::Display for CreateFunction {
3269    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3270        write!(
3271            f,
3272            "CREATE {or_alter}{or_replace}{temp}FUNCTION {if_not_exists}{name}",
3273            name = self.name,
3274            temp = if self.temporary { "TEMPORARY " } else { "" },
3275            or_alter = if self.or_alter { "OR ALTER " } else { "" },
3276            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
3277            if_not_exists = if self.if_not_exists {
3278                "IF NOT EXISTS "
3279            } else {
3280                ""
3281            },
3282        )?;
3283        if let Some(args) = &self.args {
3284            write!(f, "({})", display_comma_separated(args))?;
3285        }
3286        if let Some(return_type) = &self.return_type {
3287            write!(f, " RETURNS {return_type}")?;
3288        }
3289        if let Some(determinism_specifier) = &self.determinism_specifier {
3290            write!(f, " {determinism_specifier}")?;
3291        }
3292        if let Some(language) = &self.language {
3293            write!(f, " LANGUAGE {language}")?;
3294        }
3295        if let Some(behavior) = &self.behavior {
3296            write!(f, " {behavior}")?;
3297        }
3298        if let Some(called_on_null) = &self.called_on_null {
3299            write!(f, " {called_on_null}")?;
3300        }
3301        if let Some(parallel) = &self.parallel {
3302            write!(f, " {parallel}")?;
3303        }
3304        if let Some(security) = &self.security {
3305            write!(f, " {security}")?;
3306        }
3307        for set_param in &self.set_params {
3308            write!(f, " {set_param}")?;
3309        }
3310        if let Some(remote_connection) = &self.remote_connection {
3311            write!(f, " REMOTE WITH CONNECTION {remote_connection}")?;
3312        }
3313        if let Some(CreateFunctionBody::AsBeforeOptions { body, link_symbol }) = &self.function_body
3314        {
3315            write!(f, " AS {body}")?;
3316            if let Some(link_symbol) = link_symbol {
3317                write!(f, ", {link_symbol}")?;
3318            }
3319        }
3320        if let Some(CreateFunctionBody::Return(function_body)) = &self.function_body {
3321            write!(f, " RETURN {function_body}")?;
3322        }
3323        if let Some(CreateFunctionBody::AsReturnExpr(function_body)) = &self.function_body {
3324            write!(f, " AS RETURN {function_body}")?;
3325        }
3326        if let Some(CreateFunctionBody::AsReturnSelect(function_body)) = &self.function_body {
3327            write!(f, " AS RETURN {function_body}")?;
3328        }
3329        if let Some(using) = &self.using {
3330            write!(f, " {using}")?;
3331        }
3332        if let Some(options) = &self.options {
3333            write!(
3334                f,
3335                " OPTIONS({})",
3336                display_comma_separated(options.as_slice())
3337            )?;
3338        }
3339        if let Some(CreateFunctionBody::AsAfterOptions(function_body)) = &self.function_body {
3340            write!(f, " AS {function_body}")?;
3341        }
3342        if let Some(CreateFunctionBody::AsBeginEnd(bes)) = &self.function_body {
3343            write!(f, " AS {bes}")?;
3344        }
3345        Ok(())
3346    }
3347}
3348
3349/// ```sql
3350/// CREATE CONNECTOR [IF NOT EXISTS] connector_name
3351/// [TYPE datasource_type]
3352/// [URL datasource_url]
3353/// [COMMENT connector_comment]
3354/// [WITH DCPROPERTIES(property_name=property_value, ...)]
3355/// ```
3356///
3357/// [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
3358#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3359#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3360#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3361pub struct CreateConnector {
3362    pub name: Ident,
3363    pub if_not_exists: bool,
3364    pub connector_type: Option<String>,
3365    pub url: Option<String>,
3366    pub comment: Option<CommentDef>,
3367    pub with_dcproperties: Option<Vec<SqlOption>>,
3368}
3369
3370impl fmt::Display for CreateConnector {
3371    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3372        write!(
3373            f,
3374            "CREATE CONNECTOR {if_not_exists}{name}",
3375            if_not_exists = if self.if_not_exists {
3376                "IF NOT EXISTS "
3377            } else {
3378                ""
3379            },
3380            name = self.name,
3381        )?;
3382
3383        if let Some(connector_type) = &self.connector_type {
3384            write!(f, " TYPE '{connector_type}'")?;
3385        }
3386
3387        if let Some(url) = &self.url {
3388            write!(f, " URL '{url}'")?;
3389        }
3390
3391        if let Some(comment) = &self.comment {
3392            write!(f, " COMMENT = '{comment}'")?;
3393        }
3394
3395        if let Some(with_dcproperties) = &self.with_dcproperties {
3396            write!(
3397                f,
3398                " WITH DCPROPERTIES({})",
3399                display_comma_separated(with_dcproperties)
3400            )?;
3401        }
3402
3403        Ok(())
3404    }
3405}
3406
3407/// An `ALTER SCHEMA` (`Statement::AlterSchema`) operation.
3408///
3409/// See [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#alter_schema_collate_statement)
3410/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterschema.html)
3411#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3412#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3413#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3414pub enum AlterSchemaOperation {
3415    SetDefaultCollate {
3416        collate: Expr,
3417    },
3418    AddReplica {
3419        replica: Ident,
3420        options: Option<Vec<SqlOption>>,
3421    },
3422    DropReplica {
3423        replica: Ident,
3424    },
3425    SetOptionsParens {
3426        options: Vec<SqlOption>,
3427    },
3428    Rename {
3429        name: ObjectName,
3430    },
3431    OwnerTo {
3432        owner: Owner,
3433    },
3434}
3435
3436impl fmt::Display for AlterSchemaOperation {
3437    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3438        match self {
3439            AlterSchemaOperation::SetDefaultCollate { collate } => {
3440                write!(f, "SET DEFAULT COLLATE {collate}")
3441            }
3442            AlterSchemaOperation::AddReplica { replica, options } => {
3443                write!(f, "ADD REPLICA {replica}")?;
3444                if let Some(options) = options {
3445                    write!(f, " OPTIONS ({})", display_comma_separated(options))?;
3446                }
3447                Ok(())
3448            }
3449            AlterSchemaOperation::DropReplica { replica } => write!(f, "DROP REPLICA {replica}"),
3450            AlterSchemaOperation::SetOptionsParens { options } => {
3451                write!(f, "SET OPTIONS ({})", display_comma_separated(options))
3452            }
3453            AlterSchemaOperation::Rename { name } => write!(f, "RENAME TO {name}"),
3454            AlterSchemaOperation::OwnerTo { owner } => write!(f, "OWNER TO {owner}"),
3455        }
3456    }
3457}
3458/// `RenameTableNameKind` is the kind used in an `ALTER TABLE _ RENAME` statement.
3459///
3460/// Note: [MySQL] is the only database that supports the AS keyword for this operation.
3461///
3462/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
3463#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3464#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3465#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3466pub enum RenameTableNameKind {
3467    As(ObjectName),
3468    To(ObjectName),
3469}
3470
3471impl fmt::Display for RenameTableNameKind {
3472    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3473        match self {
3474            RenameTableNameKind::As(name) => write!(f, "AS {name}"),
3475            RenameTableNameKind::To(name) => write!(f, "TO {name}"),
3476        }
3477    }
3478}
3479
3480#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3481#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3482#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3483pub struct AlterSchema {
3484    pub name: ObjectName,
3485    pub if_exists: bool,
3486    pub operations: Vec<AlterSchemaOperation>,
3487}
3488
3489impl fmt::Display for AlterSchema {
3490    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3491        write!(f, "ALTER SCHEMA ")?;
3492        if self.if_exists {
3493            write!(f, "IF EXISTS ")?;
3494        }
3495        write!(f, "{}", self.name)?;
3496        for operation in &self.operations {
3497            write!(f, " {operation}")?;
3498        }
3499
3500        Ok(())
3501    }
3502}
3503
3504impl Spanned for RenameTableNameKind {
3505    fn span(&self) -> Span {
3506        match self {
3507            RenameTableNameKind::As(name) => name.span(),
3508            RenameTableNameKind::To(name) => name.span(),
3509        }
3510    }
3511}
3512
3513#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3514#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3515#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3516/// Whether the syntax used for the trigger object (ROW or STATEMENT) is `FOR` or `FOR EACH`.
3517pub enum TriggerObjectKind {
3518    /// The `FOR` syntax is used.
3519    For(TriggerObject),
3520    /// The `FOR EACH` syntax is used.
3521    ForEach(TriggerObject),
3522}
3523
3524impl Display for TriggerObjectKind {
3525    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3526        match self {
3527            TriggerObjectKind::For(obj) => write!(f, "FOR {obj}"),
3528            TriggerObjectKind::ForEach(obj) => write!(f, "FOR EACH {obj}"),
3529        }
3530    }
3531}
3532
3533#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3534#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3535#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3536/// CREATE TRIGGER
3537///
3538/// Examples:
3539///
3540/// ```sql
3541/// CREATE TRIGGER trigger_name
3542/// BEFORE INSERT ON table_name
3543/// FOR EACH ROW
3544/// EXECUTE FUNCTION trigger_function();
3545/// ```
3546///
3547/// Postgres: <https://www.postgresql.org/docs/current/sql-createtrigger.html>
3548/// SQL Server: <https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql>
3549pub struct CreateTrigger {
3550    /// True if this is a `CREATE OR ALTER TRIGGER` statement
3551    ///
3552    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql?view=sql-server-ver16#arguments)
3553    pub or_alter: bool,
3554    /// True if this is a temporary trigger.
3555    ///
3556    /// Examples:
3557    ///
3558    /// ```sql
3559    /// CREATE TEMP TRIGGER trigger_name
3560    /// ```
3561    ///
3562    /// or
3563    ///
3564    /// ```sql
3565    /// CREATE TEMPORARY TRIGGER trigger_name;
3566    /// CREATE TEMP TRIGGER trigger_name;
3567    /// ```
3568    ///
3569    /// [SQLite](https://sqlite.org/lang_createtrigger.html#temp_triggers_on_non_temp_tables)
3570    pub temporary: bool,
3571    /// The `OR REPLACE` clause is used to re-create the trigger if it already exists.
3572    ///
3573    /// Example:
3574    /// ```sql
3575    /// CREATE OR REPLACE TRIGGER trigger_name
3576    /// AFTER INSERT ON table_name
3577    /// FOR EACH ROW
3578    /// EXECUTE FUNCTION trigger_function();
3579    /// ```
3580    pub or_replace: bool,
3581    /// The `CONSTRAINT` keyword is used to create a trigger as a constraint.
3582    pub is_constraint: bool,
3583    /// The name of the trigger to be created.
3584    pub name: ObjectName,
3585    /// Determines whether the function is called before, after, or instead of the event.
3586    ///
3587    /// Example of BEFORE:
3588    ///
3589    /// ```sql
3590    /// CREATE TRIGGER trigger_name
3591    /// BEFORE INSERT ON table_name
3592    /// FOR EACH ROW
3593    /// EXECUTE FUNCTION trigger_function();
3594    /// ```
3595    ///
3596    /// Example of AFTER:
3597    ///
3598    /// ```sql
3599    /// CREATE TRIGGER trigger_name
3600    /// AFTER INSERT ON table_name
3601    /// FOR EACH ROW
3602    /// EXECUTE FUNCTION trigger_function();
3603    /// ```
3604    ///
3605    /// Example of INSTEAD OF:
3606    ///
3607    /// ```sql
3608    /// CREATE TRIGGER trigger_name
3609    /// INSTEAD OF INSERT ON table_name
3610    /// FOR EACH ROW
3611    /// EXECUTE FUNCTION trigger_function();
3612    /// ```
3613    pub period: Option<TriggerPeriod>,
3614    /// Whether the trigger period was specified before the target table name.
3615    /// This does not refer to whether the period is BEFORE, AFTER, or INSTEAD OF,
3616    /// but rather the position of the period clause in relation to the table name.
3617    ///
3618    /// ```sql
3619    /// -- period_before_table == true: Postgres, MySQL, and standard SQL
3620    /// CREATE TRIGGER t BEFORE INSERT ON table_name ...;
3621    /// -- period_before_table == false: MSSQL
3622    /// CREATE TRIGGER t ON table_name BEFORE INSERT ...;
3623    /// ```
3624    pub period_before_table: bool,
3625    /// Multiple events can be specified using OR, such as `INSERT`, `UPDATE`, `DELETE`, or `TRUNCATE`.
3626    pub events: Vec<TriggerEvent>,
3627    /// The table on which the trigger is to be created.
3628    pub table_name: ObjectName,
3629    /// The optional referenced table name that can be referenced via
3630    /// the `FROM` keyword.
3631    pub referenced_table_name: Option<ObjectName>,
3632    /// This keyword immediately precedes the declaration of one or two relation names that provide access to the transition relations of the triggering statement.
3633    pub referencing: Vec<TriggerReferencing>,
3634    /// This specifies whether the trigger function should be fired once for
3635    /// every row affected by the trigger event, or just once per SQL statement.
3636    /// This is optional in some SQL dialects, such as SQLite, and if not specified, in
3637    /// those cases, the implied default is `FOR EACH ROW`.
3638    pub trigger_object: Option<TriggerObjectKind>,
3639    ///  Triggering conditions
3640    pub condition: Option<Expr>,
3641    /// Execute logic block
3642    pub exec_body: Option<TriggerExecBody>,
3643    /// For MSSQL and dialects where statements are preceded by `AS`
3644    pub statements_as: bool,
3645    /// For SQL dialects with statement(s) for a body
3646    pub statements: Option<ConditionalStatements>,
3647    /// The characteristic of the trigger, which include whether the trigger is `DEFERRABLE`, `INITIALLY DEFERRED`, or `INITIALLY IMMEDIATE`,
3648    pub characteristics: Option<ConstraintCharacteristics>,
3649}
3650
3651impl Display for CreateTrigger {
3652    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3653        let CreateTrigger {
3654            or_alter,
3655            temporary,
3656            or_replace,
3657            is_constraint,
3658            name,
3659            period_before_table,
3660            period,
3661            events,
3662            table_name,
3663            referenced_table_name,
3664            referencing,
3665            trigger_object,
3666            condition,
3667            exec_body,
3668            statements_as,
3669            statements,
3670            characteristics,
3671        } = self;
3672        write!(
3673            f,
3674            "CREATE {temporary}{or_alter}{or_replace}{is_constraint}TRIGGER {name} ",
3675            temporary = if *temporary { "TEMPORARY " } else { "" },
3676            or_alter = if *or_alter { "OR ALTER " } else { "" },
3677            or_replace = if *or_replace { "OR REPLACE " } else { "" },
3678            is_constraint = if *is_constraint { "CONSTRAINT " } else { "" },
3679        )?;
3680
3681        if *period_before_table {
3682            if let Some(p) = period {
3683                write!(f, "{p} ")?;
3684            }
3685            if !events.is_empty() {
3686                write!(f, "{} ", display_separated(events, " OR "))?;
3687            }
3688            write!(f, "ON {table_name}")?;
3689        } else {
3690            write!(f, "ON {table_name} ")?;
3691            if let Some(p) = period {
3692                write!(f, "{p}")?;
3693            }
3694            if !events.is_empty() {
3695                write!(f, " {}", display_separated(events, ", "))?;
3696            }
3697        }
3698
3699        if let Some(referenced_table_name) = referenced_table_name {
3700            write!(f, " FROM {referenced_table_name}")?;
3701        }
3702
3703        if let Some(characteristics) = characteristics {
3704            write!(f, " {characteristics}")?;
3705        }
3706
3707        if !referencing.is_empty() {
3708            write!(f, " REFERENCING {}", display_separated(referencing, " "))?;
3709        }
3710
3711        if let Some(trigger_object) = trigger_object {
3712            write!(f, " {trigger_object}")?;
3713        }
3714        if let Some(condition) = condition {
3715            write!(f, " WHEN {condition}")?;
3716        }
3717        if let Some(exec_body) = exec_body {
3718            write!(f, " EXECUTE {exec_body}")?;
3719        }
3720        if let Some(statements) = statements {
3721            if *statements_as {
3722                write!(f, " AS")?;
3723            }
3724            write!(f, " {statements}")?;
3725        }
3726        Ok(())
3727    }
3728}
3729
3730#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3731#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3732#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3733/// DROP TRIGGER
3734///
3735/// ```sql
3736/// DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
3737/// ```
3738///
3739pub struct DropTrigger {
3740    /// Whether to include the `IF EXISTS` clause.
3741    pub if_exists: bool,
3742    /// The name of the trigger to be dropped.
3743    pub trigger_name: ObjectName,
3744    /// The name of the table from which the trigger is to be dropped.
3745    pub table_name: Option<ObjectName>,
3746    /// `CASCADE` or `RESTRICT`
3747    pub option: Option<ReferentialAction>,
3748}
3749
3750impl fmt::Display for DropTrigger {
3751    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3752        let DropTrigger {
3753            if_exists,
3754            trigger_name,
3755            table_name,
3756            option,
3757        } = self;
3758        write!(f, "DROP TRIGGER")?;
3759        if *if_exists {
3760            write!(f, " IF EXISTS")?;
3761        }
3762        match &table_name {
3763            Some(table_name) => write!(f, " {trigger_name} ON {table_name}")?,
3764            None => write!(f, " {trigger_name}")?,
3765        };
3766        if let Some(option) = option {
3767            write!(f, " {option}")?;
3768        }
3769        Ok(())
3770    }
3771}
3772
3773/// A `TRUNCATE` statement.
3774///
3775/// ```sql
3776/// TRUNCATE TABLE table_names [PARTITION (partitions)] [RESTART IDENTITY | CONTINUE IDENTITY] [CASCADE | RESTRICT] [ON CLUSTER cluster_name]
3777/// ```
3778#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3779#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3780#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3781pub struct Truncate {
3782    /// Table names to truncate
3783    pub table_names: Vec<super::TruncateTableTarget>,
3784    /// Optional partition specification
3785    pub partitions: Option<Vec<Expr>>,
3786    /// TABLE - optional keyword
3787    pub table: bool,
3788    /// Postgres-specific option: [ RESTART IDENTITY | CONTINUE IDENTITY ]
3789    pub identity: Option<super::TruncateIdentityOption>,
3790    /// Postgres-specific option: [ CASCADE | RESTRICT ]
3791    pub cascade: Option<super::CascadeOption>,
3792    /// ClickHouse-specific option: [ ON CLUSTER cluster_name ]
3793    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/truncate/)
3794    pub on_cluster: Option<Ident>,
3795}
3796
3797impl fmt::Display for Truncate {
3798    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3799        let table = if self.table { "TABLE " } else { "" };
3800
3801        write!(
3802            f,
3803            "TRUNCATE {table}{table_names}",
3804            table_names = display_comma_separated(&self.table_names)
3805        )?;
3806
3807        if let Some(identity) = &self.identity {
3808            match identity {
3809                super::TruncateIdentityOption::Restart => write!(f, " RESTART IDENTITY")?,
3810                super::TruncateIdentityOption::Continue => write!(f, " CONTINUE IDENTITY")?,
3811            }
3812        }
3813        if let Some(cascade) = &self.cascade {
3814            match cascade {
3815                super::CascadeOption::Cascade => write!(f, " CASCADE")?,
3816                super::CascadeOption::Restrict => write!(f, " RESTRICT")?,
3817            }
3818        }
3819
3820        if let Some(ref parts) = &self.partitions {
3821            if !parts.is_empty() {
3822                write!(f, " PARTITION ({})", display_comma_separated(parts))?;
3823            }
3824        }
3825        if let Some(on_cluster) = &self.on_cluster {
3826            write!(f, " ON CLUSTER {on_cluster}")?;
3827        }
3828        Ok(())
3829    }
3830}
3831
3832impl Spanned for Truncate {
3833    fn span(&self) -> Span {
3834        Span::union_iter(
3835            self.table_names.iter().map(|i| i.name.span()).chain(
3836                self.partitions
3837                    .iter()
3838                    .flat_map(|i| i.iter().map(|k| k.span())),
3839            ),
3840        )
3841    }
3842}
3843
3844/// An `MSCK` statement.
3845///
3846/// ```sql
3847/// MSCK [REPAIR] TABLE table_name [ADD|DROP|SYNC PARTITIONS]
3848/// ```
3849/// MSCK (Hive) - MetaStore Check command
3850#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3851#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3852#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3853pub struct Msck {
3854    /// Table name to check
3855    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
3856    pub table_name: ObjectName,
3857    /// Whether to repair the table
3858    pub repair: bool,
3859    /// Partition action (ADD, DROP, or SYNC)
3860    pub partition_action: Option<super::AddDropSync>,
3861}
3862
3863impl fmt::Display for Msck {
3864    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3865        write!(
3866            f,
3867            "MSCK {repair}TABLE {table}",
3868            repair = if self.repair { "REPAIR " } else { "" },
3869            table = self.table_name
3870        )?;
3871        if let Some(pa) = &self.partition_action {
3872            write!(f, " {pa}")?;
3873        }
3874        Ok(())
3875    }
3876}
3877
3878impl Spanned for Msck {
3879    fn span(&self) -> Span {
3880        self.table_name.span()
3881    }
3882}
3883
3884/// CREATE VIEW statement.
3885#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3886#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3887#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3888pub struct CreateView {
3889    /// True if this is a `CREATE OR ALTER VIEW` statement
3890    ///
3891    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-view-transact-sql)
3892    pub or_alter: bool,
3893    pub or_replace: bool,
3894    pub materialized: bool,
3895    /// Snowflake: SECURE view modifier
3896    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
3897    pub secure: bool,
3898    /// View name
3899    pub name: ObjectName,
3900    /// If `if_not_exists` is true, this flag is set to true if the view name comes before the `IF NOT EXISTS` clause.
3901    /// Example:
3902    /// ```sql
3903    /// CREATE VIEW myview IF NOT EXISTS AS SELECT 1`
3904    ///  ```
3905    /// Otherwise, the flag is set to false if the view name comes after the clause
3906    /// Example:
3907    /// ```sql
3908    /// CREATE VIEW IF NOT EXISTS myview AS SELECT 1`
3909    ///  ```
3910    pub name_before_not_exists: bool,
3911    pub columns: Vec<ViewColumnDef>,
3912    pub query: Box<Query>,
3913    pub options: CreateTableOptions,
3914    pub cluster_by: Vec<Ident>,
3915    /// Snowflake: Views can have comments in Snowflake.
3916    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
3917    pub comment: Option<String>,
3918    /// if true, has RedShift [`WITH NO SCHEMA BINDING`] clause <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_VIEW.html>
3919    pub with_no_schema_binding: bool,
3920    /// if true, has SQLite `IF NOT EXISTS` clause <https://www.sqlite.org/lang_createview.html>
3921    pub if_not_exists: bool,
3922    /// if true, has SQLite `TEMP` or `TEMPORARY` clause <https://www.sqlite.org/lang_createview.html>
3923    pub temporary: bool,
3924    /// if not None, has Clickhouse `TO` clause, specify the table into which to insert results
3925    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/view#materialized-view>
3926    pub to: Option<ObjectName>,
3927    /// MySQL: Optional parameters for the view algorithm, definer, and security context
3928    pub params: Option<CreateViewParams>,
3929}
3930
3931impl fmt::Display for CreateView {
3932    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3933        write!(
3934            f,
3935            "CREATE {or_alter}{or_replace}",
3936            or_alter = if self.or_alter { "OR ALTER " } else { "" },
3937            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
3938        )?;
3939        if let Some(ref params) = self.params {
3940            params.fmt(f)?;
3941        }
3942        write!(
3943            f,
3944            "{secure}{materialized}{temporary}VIEW {if_not_and_name}{to}",
3945            if_not_and_name = if self.if_not_exists {
3946                if self.name_before_not_exists {
3947                    format!("{} IF NOT EXISTS", self.name)
3948                } else {
3949                    format!("IF NOT EXISTS {}", self.name)
3950                }
3951            } else {
3952                format!("{}", self.name)
3953            },
3954            secure = if self.secure { "SECURE " } else { "" },
3955            materialized = if self.materialized {
3956                "MATERIALIZED "
3957            } else {
3958                ""
3959            },
3960            temporary = if self.temporary { "TEMPORARY " } else { "" },
3961            to = self
3962                .to
3963                .as_ref()
3964                .map(|to| format!(" TO {to}"))
3965                .unwrap_or_default()
3966        )?;
3967        if !self.columns.is_empty() {
3968            write!(f, " ({})", display_comma_separated(&self.columns))?;
3969        }
3970        if matches!(self.options, CreateTableOptions::With(_)) {
3971            write!(f, " {}", self.options)?;
3972        }
3973        if let Some(ref comment) = self.comment {
3974            write!(f, " COMMENT = '{}'", escape_single_quote_string(comment))?;
3975        }
3976        if !self.cluster_by.is_empty() {
3977            write!(
3978                f,
3979                " CLUSTER BY ({})",
3980                display_comma_separated(&self.cluster_by)
3981            )?;
3982        }
3983        if matches!(self.options, CreateTableOptions::Options(_)) {
3984            write!(f, " {}", self.options)?;
3985        }
3986        f.write_str(" AS")?;
3987        SpaceOrNewline.fmt(f)?;
3988        self.query.fmt(f)?;
3989        if self.with_no_schema_binding {
3990            write!(f, " WITH NO SCHEMA BINDING")?;
3991        }
3992        Ok(())
3993    }
3994}
3995
3996/// CREATE EXTENSION statement
3997/// Note: this is a PostgreSQL-specific statement
3998#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3999#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4000#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4001pub struct CreateExtension {
4002    pub name: Ident,
4003    pub if_not_exists: bool,
4004    pub cascade: bool,
4005    pub schema: Option<Ident>,
4006    pub version: Option<Ident>,
4007}
4008
4009impl fmt::Display for CreateExtension {
4010    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4011        write!(
4012            f,
4013            "CREATE EXTENSION {if_not_exists}{name}",
4014            if_not_exists = if self.if_not_exists {
4015                "IF NOT EXISTS "
4016            } else {
4017                ""
4018            },
4019            name = self.name
4020        )?;
4021        if self.cascade || self.schema.is_some() || self.version.is_some() {
4022            write!(f, " WITH")?;
4023
4024            if let Some(name) = &self.schema {
4025                write!(f, " SCHEMA {name}")?;
4026            }
4027            if let Some(version) = &self.version {
4028                write!(f, " VERSION {version}")?;
4029            }
4030            if self.cascade {
4031                write!(f, " CASCADE")?;
4032            }
4033        }
4034
4035        Ok(())
4036    }
4037}
4038
4039impl Spanned for CreateExtension {
4040    fn span(&self) -> Span {
4041        Span::empty()
4042    }
4043}
4044
4045/// DROP EXTENSION statement  
4046/// Note: this is a PostgreSQL-specific statement
4047///
4048/// # References
4049///
4050/// PostgreSQL Documentation:
4051/// <https://www.postgresql.org/docs/current/sql-dropextension.html>
4052#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4053#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4054#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4055pub struct DropExtension {
4056    pub names: Vec<Ident>,
4057    pub if_exists: bool,
4058    /// `CASCADE` or `RESTRICT`
4059    pub cascade_or_restrict: Option<ReferentialAction>,
4060}
4061
4062impl fmt::Display for DropExtension {
4063    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4064        write!(f, "DROP EXTENSION")?;
4065        if self.if_exists {
4066            write!(f, " IF EXISTS")?;
4067        }
4068        write!(f, " {}", display_comma_separated(&self.names))?;
4069        if let Some(cascade_or_restrict) = &self.cascade_or_restrict {
4070            write!(f, " {cascade_or_restrict}")?;
4071        }
4072        Ok(())
4073    }
4074}
4075
4076impl Spanned for DropExtension {
4077    fn span(&self) -> Span {
4078        Span::empty()
4079    }
4080}
4081
4082/// Table type for ALTER TABLE statements.
4083/// Used to distinguish between regular tables, Iceberg tables, and Dynamic tables.
4084#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4085#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4086#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4087pub enum AlterTableType {
4088    /// Iceberg table type
4089    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
4090    Iceberg,
4091    /// Dynamic table type
4092    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-dynamic-table>
4093    Dynamic,
4094    /// External table type
4095    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-external-table>
4096    External,
4097}
4098
4099/// ALTER TABLE statement
4100#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4101#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4102#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4103pub struct AlterTable {
4104    /// Table name
4105    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
4106    pub name: ObjectName,
4107    pub if_exists: bool,
4108    pub only: bool,
4109    pub operations: Vec<AlterTableOperation>,
4110    pub location: Option<HiveSetLocation>,
4111    /// ClickHouse dialect supports `ON CLUSTER` clause for ALTER TABLE
4112    /// For example: `ALTER TABLE table_name ON CLUSTER cluster_name ADD COLUMN c UInt32`
4113    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/update)
4114    pub on_cluster: Option<Ident>,
4115    /// Table type: None for regular tables, Some(AlterTableType) for Iceberg or Dynamic tables
4116    pub table_type: Option<AlterTableType>,
4117    /// Token that represents the end of the statement (semicolon or EOF)
4118    pub end_token: AttachedToken,
4119}
4120
4121impl fmt::Display for AlterTable {
4122    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4123        match &self.table_type {
4124            Some(AlterTableType::Iceberg) => write!(f, "ALTER ICEBERG TABLE ")?,
4125            Some(AlterTableType::Dynamic) => write!(f, "ALTER DYNAMIC TABLE ")?,
4126            Some(AlterTableType::External) => write!(f, "ALTER EXTERNAL TABLE ")?,
4127            None => write!(f, "ALTER TABLE ")?,
4128        }
4129
4130        if self.if_exists {
4131            write!(f, "IF EXISTS ")?;
4132        }
4133        if self.only {
4134            write!(f, "ONLY ")?;
4135        }
4136        write!(f, "{} ", &self.name)?;
4137        if let Some(cluster) = &self.on_cluster {
4138            write!(f, "ON CLUSTER {cluster} ")?;
4139        }
4140        write!(f, "{}", display_comma_separated(&self.operations))?;
4141        if let Some(loc) = &self.location {
4142            write!(f, " {loc}")?
4143        }
4144        Ok(())
4145    }
4146}
4147
4148/// DROP FUNCTION statement
4149#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4150#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4151#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4152pub struct DropFunction {
4153    pub if_exists: bool,
4154    /// One or more functions to drop
4155    pub func_desc: Vec<FunctionDesc>,
4156    /// `CASCADE` or `RESTRICT`
4157    pub drop_behavior: Option<DropBehavior>,
4158}
4159
4160impl fmt::Display for DropFunction {
4161    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4162        write!(
4163            f,
4164            "DROP FUNCTION{} {}",
4165            if self.if_exists { " IF EXISTS" } else { "" },
4166            display_comma_separated(&self.func_desc),
4167        )?;
4168        if let Some(op) = &self.drop_behavior {
4169            write!(f, " {op}")?;
4170        }
4171        Ok(())
4172    }
4173}
4174
4175impl Spanned for DropFunction {
4176    fn span(&self) -> Span {
4177        Span::empty()
4178    }
4179}
4180
4181/// CREATE OPERATOR statement
4182/// See <https://www.postgresql.org/docs/current/sql-createoperator.html>
4183#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4184#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4185#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4186pub struct CreateOperator {
4187    /// Operator name (can be schema-qualified)
4188    pub name: ObjectName,
4189    /// FUNCTION or PROCEDURE parameter (function name)
4190    pub function: ObjectName,
4191    /// Whether PROCEDURE keyword was used (vs FUNCTION)
4192    pub is_procedure: bool,
4193    /// LEFTARG parameter (left operand type)
4194    pub left_arg: Option<DataType>,
4195    /// RIGHTARG parameter (right operand type)
4196    pub right_arg: Option<DataType>,
4197    /// Operator options (COMMUTATOR, NEGATOR, RESTRICT, JOIN, HASHES, MERGES)
4198    pub options: Vec<OperatorOption>,
4199}
4200
4201/// CREATE OPERATOR FAMILY statement
4202/// See <https://www.postgresql.org/docs/current/sql-createopfamily.html>
4203#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4204#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4205#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4206pub struct CreateOperatorFamily {
4207    /// Operator family name (can be schema-qualified)
4208    pub name: ObjectName,
4209    /// Index method (btree, hash, gist, gin, etc.)
4210    pub using: Ident,
4211}
4212
4213/// CREATE OPERATOR CLASS statement
4214/// See <https://www.postgresql.org/docs/current/sql-createopclass.html>
4215#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4216#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4217#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4218pub struct CreateOperatorClass {
4219    /// Operator class name (can be schema-qualified)
4220    pub name: ObjectName,
4221    /// Whether this is the default operator class for the type
4222    pub default: bool,
4223    /// The data type
4224    pub for_type: DataType,
4225    /// Index method (btree, hash, gist, gin, etc.)
4226    pub using: Ident,
4227    /// Optional operator family name
4228    pub family: Option<ObjectName>,
4229    /// List of operator class items (operators, functions, storage)
4230    pub items: Vec<OperatorClassItem>,
4231}
4232
4233impl fmt::Display for CreateOperator {
4234    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4235        write!(f, "CREATE OPERATOR {} (", self.name)?;
4236
4237        let function_keyword = if self.is_procedure {
4238            "PROCEDURE"
4239        } else {
4240            "FUNCTION"
4241        };
4242        let mut params = vec![format!("{} = {}", function_keyword, self.function)];
4243
4244        if let Some(left_arg) = &self.left_arg {
4245            params.push(format!("LEFTARG = {}", left_arg));
4246        }
4247        if let Some(right_arg) = &self.right_arg {
4248            params.push(format!("RIGHTARG = {}", right_arg));
4249        }
4250
4251        for option in &self.options {
4252            params.push(option.to_string());
4253        }
4254
4255        write!(f, "{}", params.join(", "))?;
4256        write!(f, ")")
4257    }
4258}
4259
4260impl fmt::Display for CreateOperatorFamily {
4261    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4262        write!(
4263            f,
4264            "CREATE OPERATOR FAMILY {} USING {}",
4265            self.name, self.using
4266        )
4267    }
4268}
4269
4270impl fmt::Display for CreateOperatorClass {
4271    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4272        write!(f, "CREATE OPERATOR CLASS {}", self.name)?;
4273        if self.default {
4274            write!(f, " DEFAULT")?;
4275        }
4276        write!(f, " FOR TYPE {} USING {}", self.for_type, self.using)?;
4277        if let Some(family) = &self.family {
4278            write!(f, " FAMILY {}", family)?;
4279        }
4280        write!(f, " AS {}", display_comma_separated(&self.items))
4281    }
4282}
4283
4284/// Operator argument types for CREATE OPERATOR CLASS
4285#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4286#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4287#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4288pub struct OperatorArgTypes {
4289    pub left: DataType,
4290    pub right: DataType,
4291}
4292
4293impl fmt::Display for OperatorArgTypes {
4294    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4295        write!(f, "{}, {}", self.left, self.right)
4296    }
4297}
4298
4299/// An item in a CREATE OPERATOR CLASS statement
4300#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4301#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4302#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4303pub enum OperatorClassItem {
4304    /// `OPERATOR` clause
4305    Operator {
4306        strategy_number: u64,
4307        operator_name: ObjectName,
4308        /// Optional operator argument types
4309        op_types: Option<OperatorArgTypes>,
4310        /// `FOR SEARCH` or `FOR ORDER BY`
4311        purpose: Option<OperatorPurpose>,
4312    },
4313    /// `FUNCTION` clause
4314    Function {
4315        support_number: u64,
4316        /// Optional function argument types for the operator class
4317        op_types: Option<Vec<DataType>>,
4318        function_name: ObjectName,
4319        /// Function argument types
4320        argument_types: Vec<DataType>,
4321    },
4322    /// `STORAGE` clause
4323    Storage { storage_type: DataType },
4324}
4325
4326/// Purpose of an operator in an operator class
4327#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4328#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4329#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4330pub enum OperatorPurpose {
4331    ForSearch,
4332    ForOrderBy { sort_family: ObjectName },
4333}
4334
4335impl fmt::Display for OperatorClassItem {
4336    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4337        match self {
4338            OperatorClassItem::Operator {
4339                strategy_number,
4340                operator_name,
4341                op_types,
4342                purpose,
4343            } => {
4344                write!(f, "OPERATOR {strategy_number} {operator_name}")?;
4345                if let Some(types) = op_types {
4346                    write!(f, " ({types})")?;
4347                }
4348                if let Some(purpose) = purpose {
4349                    write!(f, " {purpose}")?;
4350                }
4351                Ok(())
4352            }
4353            OperatorClassItem::Function {
4354                support_number,
4355                op_types,
4356                function_name,
4357                argument_types,
4358            } => {
4359                write!(f, "FUNCTION {support_number}")?;
4360                if let Some(types) = op_types {
4361                    write!(f, " ({})", display_comma_separated(types))?;
4362                }
4363                write!(f, " {function_name}")?;
4364                if !argument_types.is_empty() {
4365                    write!(f, "({})", display_comma_separated(argument_types))?;
4366                }
4367                Ok(())
4368            }
4369            OperatorClassItem::Storage { storage_type } => {
4370                write!(f, "STORAGE {storage_type}")
4371            }
4372        }
4373    }
4374}
4375
4376impl fmt::Display for OperatorPurpose {
4377    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4378        match self {
4379            OperatorPurpose::ForSearch => write!(f, "FOR SEARCH"),
4380            OperatorPurpose::ForOrderBy { sort_family } => {
4381                write!(f, "FOR ORDER BY {sort_family}")
4382            }
4383        }
4384    }
4385}
4386
4387/// `DROP OPERATOR` statement
4388/// See <https://www.postgresql.org/docs/current/sql-dropoperator.html>
4389#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4390#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4391#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4392pub struct DropOperator {
4393    /// `IF EXISTS` clause
4394    pub if_exists: bool,
4395    /// One or more operators to drop with their signatures
4396    pub operators: Vec<DropOperatorSignature>,
4397    /// `CASCADE or RESTRICT`
4398    pub drop_behavior: Option<DropBehavior>,
4399}
4400
4401/// Operator signature for a `DROP OPERATOR` statement
4402#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4403#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4404#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4405pub struct DropOperatorSignature {
4406    /// Operator name
4407    pub name: ObjectName,
4408    /// Left operand type
4409    pub left_type: Option<DataType>,
4410    /// Right operand type
4411    pub right_type: DataType,
4412}
4413
4414impl fmt::Display for DropOperatorSignature {
4415    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4416        write!(f, "{} (", self.name)?;
4417        if let Some(left_type) = &self.left_type {
4418            write!(f, "{}", left_type)?;
4419        } else {
4420            write!(f, "NONE")?;
4421        }
4422        write!(f, ", {})", self.right_type)
4423    }
4424}
4425
4426impl fmt::Display for DropOperator {
4427    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4428        write!(f, "DROP OPERATOR")?;
4429        if self.if_exists {
4430            write!(f, " IF EXISTS")?;
4431        }
4432        write!(f, " {}", display_comma_separated(&self.operators))?;
4433        if let Some(drop_behavior) = &self.drop_behavior {
4434            write!(f, " {}", drop_behavior)?;
4435        }
4436        Ok(())
4437    }
4438}
4439
4440impl Spanned for DropOperator {
4441    fn span(&self) -> Span {
4442        Span::empty()
4443    }
4444}
4445
4446/// `DROP OPERATOR FAMILY` statement
4447/// See <https://www.postgresql.org/docs/current/sql-dropopfamily.html>
4448#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4449#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4450#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4451pub struct DropOperatorFamily {
4452    /// `IF EXISTS` clause
4453    pub if_exists: bool,
4454    /// One or more operator families to drop
4455    pub names: Vec<ObjectName>,
4456    /// Index method (btree, hash, gist, gin, etc.)
4457    pub using: Ident,
4458    /// `CASCADE or RESTRICT`
4459    pub drop_behavior: Option<DropBehavior>,
4460}
4461
4462impl fmt::Display for DropOperatorFamily {
4463    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4464        write!(f, "DROP OPERATOR FAMILY")?;
4465        if self.if_exists {
4466            write!(f, " IF EXISTS")?;
4467        }
4468        write!(f, " {}", display_comma_separated(&self.names))?;
4469        write!(f, " USING {}", self.using)?;
4470        if let Some(drop_behavior) = &self.drop_behavior {
4471            write!(f, " {}", drop_behavior)?;
4472        }
4473        Ok(())
4474    }
4475}
4476
4477impl Spanned for DropOperatorFamily {
4478    fn span(&self) -> Span {
4479        Span::empty()
4480    }
4481}
4482
4483/// `DROP OPERATOR CLASS` statement
4484/// See <https://www.postgresql.org/docs/current/sql-dropopclass.html>
4485#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4486#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4487#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4488pub struct DropOperatorClass {
4489    /// `IF EXISTS` clause
4490    pub if_exists: bool,
4491    /// One or more operator classes to drop
4492    pub names: Vec<ObjectName>,
4493    /// Index method (btree, hash, gist, gin, etc.)
4494    pub using: Ident,
4495    /// `CASCADE or RESTRICT`
4496    pub drop_behavior: Option<DropBehavior>,
4497}
4498
4499impl fmt::Display for DropOperatorClass {
4500    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4501        write!(f, "DROP OPERATOR CLASS")?;
4502        if self.if_exists {
4503            write!(f, " IF EXISTS")?;
4504        }
4505        write!(f, " {}", display_comma_separated(&self.names))?;
4506        write!(f, " USING {}", self.using)?;
4507        if let Some(drop_behavior) = &self.drop_behavior {
4508            write!(f, " {}", drop_behavior)?;
4509        }
4510        Ok(())
4511    }
4512}
4513
4514impl Spanned for DropOperatorClass {
4515    fn span(&self) -> Span {
4516        Span::empty()
4517    }
4518}
4519
4520/// An item in an ALTER OPERATOR FAMILY ADD 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 enum OperatorFamilyItem {
4525    /// `OPERATOR` clause
4526    Operator {
4527        strategy_number: u64,
4528        operator_name: ObjectName,
4529        /// Operator argument types
4530        op_types: Vec<DataType>,
4531        /// `FOR SEARCH` or `FOR ORDER BY`
4532        purpose: Option<OperatorPurpose>,
4533    },
4534    /// `FUNCTION` clause
4535    Function {
4536        support_number: u64,
4537        /// Optional operator argument types for the function
4538        op_types: Option<Vec<DataType>>,
4539        function_name: ObjectName,
4540        /// Function argument types
4541        argument_types: Vec<DataType>,
4542    },
4543}
4544
4545/// An item in an ALTER OPERATOR FAMILY DROP statement
4546#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4547#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4548#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4549pub enum OperatorFamilyDropItem {
4550    /// `OPERATOR` clause
4551    Operator {
4552        strategy_number: u64,
4553        /// Operator argument types
4554        op_types: Vec<DataType>,
4555    },
4556    /// `FUNCTION` clause
4557    Function {
4558        support_number: u64,
4559        /// Operator argument types for the function
4560        op_types: Vec<DataType>,
4561    },
4562}
4563
4564impl fmt::Display for OperatorFamilyItem {
4565    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4566        match self {
4567            OperatorFamilyItem::Operator {
4568                strategy_number,
4569                operator_name,
4570                op_types,
4571                purpose,
4572            } => {
4573                write!(
4574                    f,
4575                    "OPERATOR {strategy_number} {operator_name} ({})",
4576                    display_comma_separated(op_types)
4577                )?;
4578                if let Some(purpose) = purpose {
4579                    write!(f, " {purpose}")?;
4580                }
4581                Ok(())
4582            }
4583            OperatorFamilyItem::Function {
4584                support_number,
4585                op_types,
4586                function_name,
4587                argument_types,
4588            } => {
4589                write!(f, "FUNCTION {support_number}")?;
4590                if let Some(types) = op_types {
4591                    write!(f, " ({})", display_comma_separated(types))?;
4592                }
4593                write!(f, " {function_name}")?;
4594                if !argument_types.is_empty() {
4595                    write!(f, "({})", display_comma_separated(argument_types))?;
4596                }
4597                Ok(())
4598            }
4599        }
4600    }
4601}
4602
4603impl fmt::Display for OperatorFamilyDropItem {
4604    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4605        match self {
4606            OperatorFamilyDropItem::Operator {
4607                strategy_number,
4608                op_types,
4609            } => {
4610                write!(
4611                    f,
4612                    "OPERATOR {strategy_number} ({})",
4613                    display_comma_separated(op_types)
4614                )
4615            }
4616            OperatorFamilyDropItem::Function {
4617                support_number,
4618                op_types,
4619            } => {
4620                write!(
4621                    f,
4622                    "FUNCTION {support_number} ({})",
4623                    display_comma_separated(op_types)
4624                )
4625            }
4626        }
4627    }
4628}
4629
4630/// `ALTER OPERATOR FAMILY` statement
4631/// See <https://www.postgresql.org/docs/current/sql-alteropfamily.html>
4632#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4633#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4634#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4635pub struct AlterOperatorFamily {
4636    /// Operator family name (can be schema-qualified)
4637    pub name: ObjectName,
4638    /// Index method (btree, hash, gist, gin, etc.)
4639    pub using: Ident,
4640    /// The operation to perform
4641    pub operation: AlterOperatorFamilyOperation,
4642}
4643
4644/// An [AlterOperatorFamily] operation
4645#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4646#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4647#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4648pub enum AlterOperatorFamilyOperation {
4649    /// `ADD { OPERATOR ... | FUNCTION ... } [, ...]`
4650    Add {
4651        /// List of operator family items to add
4652        items: Vec<OperatorFamilyItem>,
4653    },
4654    /// `DROP { OPERATOR ... | FUNCTION ... } [, ...]`
4655    Drop {
4656        /// List of operator family items to drop
4657        items: Vec<OperatorFamilyDropItem>,
4658    },
4659    /// `RENAME TO new_name`
4660    RenameTo { new_name: ObjectName },
4661    /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
4662    OwnerTo(Owner),
4663    /// `SET SCHEMA new_schema`
4664    SetSchema { schema_name: ObjectName },
4665}
4666
4667impl fmt::Display for AlterOperatorFamily {
4668    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4669        write!(
4670            f,
4671            "ALTER OPERATOR FAMILY {} USING {}",
4672            self.name, self.using
4673        )?;
4674        write!(f, " {}", self.operation)
4675    }
4676}
4677
4678impl fmt::Display for AlterOperatorFamilyOperation {
4679    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4680        match self {
4681            AlterOperatorFamilyOperation::Add { items } => {
4682                write!(f, "ADD {}", display_comma_separated(items))
4683            }
4684            AlterOperatorFamilyOperation::Drop { items } => {
4685                write!(f, "DROP {}", display_comma_separated(items))
4686            }
4687            AlterOperatorFamilyOperation::RenameTo { new_name } => {
4688                write!(f, "RENAME TO {new_name}")
4689            }
4690            AlterOperatorFamilyOperation::OwnerTo(owner) => {
4691                write!(f, "OWNER TO {owner}")
4692            }
4693            AlterOperatorFamilyOperation::SetSchema { schema_name } => {
4694                write!(f, "SET SCHEMA {schema_name}")
4695            }
4696        }
4697    }
4698}
4699
4700impl Spanned for AlterOperatorFamily {
4701    fn span(&self) -> Span {
4702        Span::empty()
4703    }
4704}