Thanks to visit codestin.com
Credit goes to docs.rs

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::{boxed::Box, string::String, vec::Vec};
23use core::fmt::{self, Write};
24
25#[cfg(feature = "serde")]
26use serde::{Deserialize, Serialize};
27
28#[cfg(feature = "visitor")]
29use sqlparser_derive::{Visit, VisitMut};
30
31use crate::ast::value::escape_single_quote_string;
32use crate::ast::{
33    display_comma_separated, display_separated, CommentDef, CreateFunctionBody,
34    CreateFunctionUsing, DataType, Expr, FunctionBehavior, FunctionCalledOnNull,
35    FunctionDeterminismSpecifier, FunctionParallel, Ident, MySQLColumnPosition, ObjectName,
36    OperateFunctionArg, OrderByExpr, ProjectionSelect, SequenceOptions, SqlOption, Tag, Value,
37    ValueWithSpan,
38};
39use crate::keywords::Keyword;
40use crate::tokenizer::Token;
41
42/// An `ALTER TABLE` (`Statement::AlterTable`) operation
43#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
44#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
45#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
46pub enum AlterTableOperation {
47    /// `ADD <table_constraint>`
48    AddConstraint(TableConstraint),
49    /// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
50    AddColumn {
51        /// `[COLUMN]`.
52        column_keyword: bool,
53        /// `[IF NOT EXISTS]`
54        if_not_exists: bool,
55        /// <column_def>.
56        column_def: ColumnDef,
57        /// MySQL `ALTER TABLE` only  [FIRST | AFTER column_name]
58        column_position: Option<MySQLColumnPosition>,
59    },
60    /// `ADD PROJECTION [IF NOT EXISTS] name ( SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY])`
61    ///
62    /// Note: this is a ClickHouse-specific operation.
63    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#add-projection)
64    AddProjection {
65        if_not_exists: bool,
66        name: Ident,
67        select: ProjectionSelect,
68    },
69    /// `DROP PROJECTION [IF EXISTS] name`
70    ///
71    /// Note: this is a ClickHouse-specific operation.
72    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#drop-projection)
73    DropProjection {
74        if_exists: bool,
75        name: Ident,
76    },
77    /// `MATERIALIZE PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
78    ///
79    ///  Note: this is a ClickHouse-specific operation.
80    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#materialize-projection)
81    MaterializeProjection {
82        if_exists: bool,
83        name: Ident,
84        partition: Option<Ident>,
85    },
86    /// `CLEAR PROJECTION [IF EXISTS] name [IN PARTITION partition_name]`
87    ///
88    /// Note: this is a ClickHouse-specific operation.
89    /// Please refer to [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#clear-projection)
90    ClearProjection {
91        if_exists: bool,
92        name: Ident,
93        partition: Option<Ident>,
94    },
95    /// `DISABLE ROW LEVEL SECURITY`
96    ///
97    /// Note: this is a PostgreSQL-specific operation.
98    DisableRowLevelSecurity,
99    /// `DISABLE RULE rewrite_rule_name`
100    ///
101    /// Note: this is a PostgreSQL-specific operation.
102    DisableRule {
103        name: Ident,
104    },
105    /// `DISABLE TRIGGER [ trigger_name | ALL | USER ]`
106    ///
107    /// Note: this is a PostgreSQL-specific operation.
108    DisableTrigger {
109        name: Ident,
110    },
111    /// `DROP CONSTRAINT [ IF EXISTS ] <name>`
112    DropConstraint {
113        if_exists: bool,
114        name: Ident,
115        drop_behavior: Option<DropBehavior>,
116    },
117    /// `DROP [ COLUMN ] [ IF EXISTS ] <column_name> [ CASCADE ]`
118    DropColumn {
119        column_name: Ident,
120        if_exists: bool,
121        drop_behavior: Option<DropBehavior>,
122    },
123    /// `ATTACH PART|PARTITION <partition_expr>`
124    /// Note: this is a ClickHouse-specific operation, please refer to
125    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/pakrtition#attach-partitionpart)
126    AttachPartition {
127        // PART is not a short form of PARTITION, it's a separate keyword
128        // which represents a physical file on disk and partition is a logical entity.
129        partition: Partition,
130    },
131    /// `DETACH PART|PARTITION <partition_expr>`
132    /// Note: this is a ClickHouse-specific operation, please refer to
133    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#detach-partitionpart)
134    DetachPartition {
135        // See `AttachPartition` for more details
136        partition: Partition,
137    },
138    /// `FREEZE PARTITION <partition_expr>`
139    /// Note: this is a ClickHouse-specific operation, please refer to
140    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#freeze-partition)
141    FreezePartition {
142        partition: Partition,
143        with_name: Option<Ident>,
144    },
145    /// `UNFREEZE PARTITION <partition_expr>`
146    /// Note: this is a ClickHouse-specific operation, please refer to
147    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#unfreeze-partition)
148    UnfreezePartition {
149        partition: Partition,
150        with_name: Option<Ident>,
151    },
152    /// `DROP PRIMARY KEY`
153    ///
154    /// Note: this is a [MySQL]-specific operation.
155    ///
156    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
157    DropPrimaryKey,
158    /// `DROP FOREIGN KEY <fk_symbol>`
159    ///
160    /// Note: this is a [MySQL]-specific operation.
161    ///
162    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
163    DropForeignKey {
164        name: Ident,
165    },
166    /// `ENABLE ALWAYS RULE rewrite_rule_name`
167    ///
168    /// Note: this is a PostgreSQL-specific operation.
169    EnableAlwaysRule {
170        name: Ident,
171    },
172    /// `ENABLE ALWAYS TRIGGER trigger_name`
173    ///
174    /// Note: this is a PostgreSQL-specific operation.
175    EnableAlwaysTrigger {
176        name: Ident,
177    },
178    /// `ENABLE REPLICA RULE rewrite_rule_name`
179    ///
180    /// Note: this is a PostgreSQL-specific operation.
181    EnableReplicaRule {
182        name: Ident,
183    },
184    /// `ENABLE REPLICA TRIGGER trigger_name`
185    ///
186    /// Note: this is a PostgreSQL-specific operation.
187    EnableReplicaTrigger {
188        name: Ident,
189    },
190    /// `ENABLE ROW LEVEL SECURITY`
191    ///
192    /// Note: this is a PostgreSQL-specific operation.
193    EnableRowLevelSecurity,
194    /// `ENABLE RULE rewrite_rule_name`
195    ///
196    /// Note: this is a PostgreSQL-specific operation.
197    EnableRule {
198        name: Ident,
199    },
200    /// `ENABLE TRIGGER [ trigger_name | ALL | USER ]`
201    ///
202    /// Note: this is a PostgreSQL-specific operation.
203    EnableTrigger {
204        name: Ident,
205    },
206    /// `RENAME TO PARTITION (partition=val)`
207    RenamePartitions {
208        old_partitions: Vec<Expr>,
209        new_partitions: Vec<Expr>,
210    },
211    /// Add Partitions
212    AddPartitions {
213        if_not_exists: bool,
214        new_partitions: Vec<Partition>,
215    },
216    DropPartitions {
217        partitions: Vec<Expr>,
218        if_exists: bool,
219    },
220    /// `RENAME [ COLUMN ] <old_column_name> TO <new_column_name>`
221    RenameColumn {
222        old_column_name: Ident,
223        new_column_name: Ident,
224    },
225    /// `RENAME TO <table_name>`
226    RenameTable {
227        table_name: ObjectName,
228    },
229    // CHANGE [ COLUMN ] <old_name> <new_name> <data_type> [ <options> ]
230    ChangeColumn {
231        old_name: Ident,
232        new_name: Ident,
233        data_type: DataType,
234        options: Vec<ColumnOption>,
235        /// MySQL `ALTER TABLE` only  [FIRST | AFTER column_name]
236        column_position: Option<MySQLColumnPosition>,
237    },
238    // CHANGE [ COLUMN ] <col_name> <data_type> [ <options> ]
239    ModifyColumn {
240        col_name: Ident,
241        data_type: DataType,
242        options: Vec<ColumnOption>,
243        /// MySQL `ALTER TABLE` only  [FIRST | AFTER column_name]
244        column_position: Option<MySQLColumnPosition>,
245    },
246    /// `RENAME CONSTRAINT <old_constraint_name> TO <new_constraint_name>`
247    ///
248    /// Note: this is a PostgreSQL-specific operation.
249    RenameConstraint {
250        old_name: Ident,
251        new_name: Ident,
252    },
253    /// `ALTER [ COLUMN ]`
254    AlterColumn {
255        column_name: Ident,
256        op: AlterColumnOperation,
257    },
258    /// 'SWAP WITH <table_name>'
259    ///
260    /// Note: this is Snowflake specific <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
261    SwapWith {
262        table_name: ObjectName,
263    },
264    /// 'SET TBLPROPERTIES ( { property_key [ = ] property_val } [, ...] )'
265    SetTblProperties {
266        table_properties: Vec<SqlOption>,
267    },
268    /// `OWNER TO { <new_owner> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
269    ///
270    /// Note: this is PostgreSQL-specific <https://www.postgresql.org/docs/current/sql-altertable.html>
271    OwnerTo {
272        new_owner: Owner,
273    },
274    /// Snowflake table clustering options
275    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-table#clustering-actions-clusteringaction>
276    ClusterBy {
277        exprs: Vec<Expr>,
278    },
279    DropClusteringKey,
280    SuspendRecluster,
281    ResumeRecluster,
282    /// `ALGORITHM [=] { DEFAULT | INSTANT | INPLACE | COPY }`
283    ///
284    /// [MySQL]-specific table alter algorithm.
285    ///
286    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
287    Algorithm {
288        equals: bool,
289        algorithm: AlterTableAlgorithm,
290    },
291
292    /// `LOCK [=] { DEFAULT | NONE | SHARED | EXCLUSIVE }`
293    ///
294    /// [MySQL]-specific table alter lock.
295    ///
296    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
297    Lock {
298        equals: bool,
299        lock: AlterTableLock,
300    },
301    /// `AUTO_INCREMENT [=] <value>`
302    ///
303    /// [MySQL]-specific table option for raising current auto increment value.
304    ///
305    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
306    AutoIncrement {
307        equals: bool,
308        value: ValueWithSpan,
309    },
310}
311
312/// An `ALTER Policy` (`Statement::AlterPolicy`) operation
313///
314/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-altertable.html)
315#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
316#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
317#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
318pub enum AlterPolicyOperation {
319    Rename {
320        new_name: Ident,
321    },
322    Apply {
323        to: Option<Vec<Owner>>,
324        using: Option<Expr>,
325        with_check: Option<Expr>,
326    },
327}
328
329impl fmt::Display for AlterPolicyOperation {
330    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
331        match self {
332            AlterPolicyOperation::Rename { new_name } => {
333                write!(f, " RENAME TO {new_name}")
334            }
335            AlterPolicyOperation::Apply {
336                to,
337                using,
338                with_check,
339            } => {
340                if let Some(to) = to {
341                    write!(f, " TO {}", display_comma_separated(to))?;
342                }
343                if let Some(using) = using {
344                    write!(f, " USING ({using})")?;
345                }
346                if let Some(with_check) = with_check {
347                    write!(f, " WITH CHECK ({with_check})")?;
348                }
349                Ok(())
350            }
351        }
352    }
353}
354
355/// [MySQL] `ALTER TABLE` algorithm.
356///
357/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
358#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
359#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
360#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
361pub enum AlterTableAlgorithm {
362    Default,
363    Instant,
364    Inplace,
365    Copy,
366}
367
368impl fmt::Display for AlterTableAlgorithm {
369    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
370        f.write_str(match self {
371            Self::Default => "DEFAULT",
372            Self::Instant => "INSTANT",
373            Self::Inplace => "INPLACE",
374            Self::Copy => "COPY",
375        })
376    }
377}
378
379/// [MySQL] `ALTER TABLE` lock.
380///
381/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
382#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
383#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
384#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
385pub enum AlterTableLock {
386    Default,
387    None,
388    Shared,
389    Exclusive,
390}
391
392impl fmt::Display for AlterTableLock {
393    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
394        f.write_str(match self {
395            Self::Default => "DEFAULT",
396            Self::None => "NONE",
397            Self::Shared => "SHARED",
398            Self::Exclusive => "EXCLUSIVE",
399        })
400    }
401}
402
403#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
404#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
405#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
406pub enum Owner {
407    Ident(Ident),
408    CurrentRole,
409    CurrentUser,
410    SessionUser,
411}
412
413impl fmt::Display for Owner {
414    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
415        match self {
416            Owner::Ident(ident) => write!(f, "{}", ident),
417            Owner::CurrentRole => write!(f, "CURRENT_ROLE"),
418            Owner::CurrentUser => write!(f, "CURRENT_USER"),
419            Owner::SessionUser => write!(f, "SESSION_USER"),
420        }
421    }
422}
423
424#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
425#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
426#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
427pub enum AlterConnectorOwner {
428    User(Ident),
429    Role(Ident),
430}
431
432impl fmt::Display for AlterConnectorOwner {
433    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
434        match self {
435            AlterConnectorOwner::User(ident) => write!(f, "USER {ident}"),
436            AlterConnectorOwner::Role(ident) => write!(f, "ROLE {ident}"),
437        }
438    }
439}
440
441#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
442#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
443#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
444pub enum AlterIndexOperation {
445    RenameIndex { index_name: ObjectName },
446}
447
448impl fmt::Display for AlterTableOperation {
449    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
450        match self {
451            AlterTableOperation::AddPartitions {
452                if_not_exists,
453                new_partitions,
454            } => write!(
455                f,
456                "ADD{ine} {}",
457                display_separated(new_partitions, " "),
458                ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
459            ),
460            AlterTableOperation::AddConstraint(c) => write!(f, "ADD {c}"),
461            AlterTableOperation::AddColumn {
462                column_keyword,
463                if_not_exists,
464                column_def,
465                column_position,
466            } => {
467                write!(f, "ADD")?;
468                if *column_keyword {
469                    write!(f, " COLUMN")?;
470                }
471                if *if_not_exists {
472                    write!(f, " IF NOT EXISTS")?;
473                }
474                write!(f, " {column_def}")?;
475
476                if let Some(position) = column_position {
477                    write!(f, " {position}")?;
478                }
479
480                Ok(())
481            }
482            AlterTableOperation::AddProjection {
483                if_not_exists,
484                name,
485                select: query,
486            } => {
487                write!(f, "ADD PROJECTION")?;
488                if *if_not_exists {
489                    write!(f, " IF NOT EXISTS")?;
490                }
491                write!(f, " {} ({})", name, query)
492            }
493            AlterTableOperation::Algorithm { equals, algorithm } => {
494                write!(
495                    f,
496                    "ALGORITHM {}{}",
497                    if *equals { "= " } else { "" },
498                    algorithm
499                )
500            }
501            AlterTableOperation::DropProjection { if_exists, name } => {
502                write!(f, "DROP PROJECTION")?;
503                if *if_exists {
504                    write!(f, " IF EXISTS")?;
505                }
506                write!(f, " {}", name)
507            }
508            AlterTableOperation::MaterializeProjection {
509                if_exists,
510                name,
511                partition,
512            } => {
513                write!(f, "MATERIALIZE PROJECTION")?;
514                if *if_exists {
515                    write!(f, " IF EXISTS")?;
516                }
517                write!(f, " {}", name)?;
518                if let Some(partition) = partition {
519                    write!(f, " IN PARTITION {}", partition)?;
520                }
521                Ok(())
522            }
523            AlterTableOperation::ClearProjection {
524                if_exists,
525                name,
526                partition,
527            } => {
528                write!(f, "CLEAR PROJECTION")?;
529                if *if_exists {
530                    write!(f, " IF EXISTS")?;
531                }
532                write!(f, " {}", name)?;
533                if let Some(partition) = partition {
534                    write!(f, " IN PARTITION {}", partition)?;
535                }
536                Ok(())
537            }
538            AlterTableOperation::AlterColumn { column_name, op } => {
539                write!(f, "ALTER COLUMN {column_name} {op}")
540            }
541            AlterTableOperation::DisableRowLevelSecurity => {
542                write!(f, "DISABLE ROW LEVEL SECURITY")
543            }
544            AlterTableOperation::DisableRule { name } => {
545                write!(f, "DISABLE RULE {name}")
546            }
547            AlterTableOperation::DisableTrigger { name } => {
548                write!(f, "DISABLE TRIGGER {name}")
549            }
550            AlterTableOperation::DropPartitions {
551                partitions,
552                if_exists,
553            } => write!(
554                f,
555                "DROP{ie} PARTITION ({})",
556                display_comma_separated(partitions),
557                ie = if *if_exists { " IF EXISTS" } else { "" }
558            ),
559            AlterTableOperation::DropConstraint {
560                if_exists,
561                name,
562                drop_behavior,
563            } => {
564                write!(
565                    f,
566                    "DROP CONSTRAINT {}{}{}",
567                    if *if_exists { "IF EXISTS " } else { "" },
568                    name,
569                    match drop_behavior {
570                        None => "",
571                        Some(DropBehavior::Restrict) => " RESTRICT",
572                        Some(DropBehavior::Cascade) => " CASCADE",
573                    }
574                )
575            }
576            AlterTableOperation::DropPrimaryKey => write!(f, "DROP PRIMARY KEY"),
577            AlterTableOperation::DropForeignKey { name } => write!(f, "DROP FOREIGN KEY {name}"),
578            AlterTableOperation::DropColumn {
579                column_name,
580                if_exists,
581                drop_behavior,
582            } => write!(
583                f,
584                "DROP COLUMN {}{}{}",
585                if *if_exists { "IF EXISTS " } else { "" },
586                column_name,
587                match drop_behavior {
588                    None => "",
589                    Some(DropBehavior::Restrict) => " RESTRICT",
590                    Some(DropBehavior::Cascade) => " CASCADE",
591                }
592            ),
593            AlterTableOperation::AttachPartition { partition } => {
594                write!(f, "ATTACH {partition}")
595            }
596            AlterTableOperation::DetachPartition { partition } => {
597                write!(f, "DETACH {partition}")
598            }
599            AlterTableOperation::EnableAlwaysRule { name } => {
600                write!(f, "ENABLE ALWAYS RULE {name}")
601            }
602            AlterTableOperation::EnableAlwaysTrigger { name } => {
603                write!(f, "ENABLE ALWAYS TRIGGER {name}")
604            }
605            AlterTableOperation::EnableReplicaRule { name } => {
606                write!(f, "ENABLE REPLICA RULE {name}")
607            }
608            AlterTableOperation::EnableReplicaTrigger { name } => {
609                write!(f, "ENABLE REPLICA TRIGGER {name}")
610            }
611            AlterTableOperation::EnableRowLevelSecurity => {
612                write!(f, "ENABLE ROW LEVEL SECURITY")
613            }
614            AlterTableOperation::EnableRule { name } => {
615                write!(f, "ENABLE RULE {name}")
616            }
617            AlterTableOperation::EnableTrigger { name } => {
618                write!(f, "ENABLE TRIGGER {name}")
619            }
620            AlterTableOperation::RenamePartitions {
621                old_partitions,
622                new_partitions,
623            } => write!(
624                f,
625                "PARTITION ({}) RENAME TO PARTITION ({})",
626                display_comma_separated(old_partitions),
627                display_comma_separated(new_partitions)
628            ),
629            AlterTableOperation::RenameColumn {
630                old_column_name,
631                new_column_name,
632            } => write!(f, "RENAME COLUMN {old_column_name} TO {new_column_name}"),
633            AlterTableOperation::RenameTable { table_name } => {
634                write!(f, "RENAME TO {table_name}")
635            }
636            AlterTableOperation::ChangeColumn {
637                old_name,
638                new_name,
639                data_type,
640                options,
641                column_position,
642            } => {
643                write!(f, "CHANGE COLUMN {old_name} {new_name} {data_type}")?;
644                if !options.is_empty() {
645                    write!(f, " {}", display_separated(options, " "))?;
646                }
647                if let Some(position) = column_position {
648                    write!(f, " {position}")?;
649                }
650
651                Ok(())
652            }
653            AlterTableOperation::ModifyColumn {
654                col_name,
655                data_type,
656                options,
657                column_position,
658            } => {
659                write!(f, "MODIFY COLUMN {col_name} {data_type}")?;
660                if !options.is_empty() {
661                    write!(f, " {}", display_separated(options, " "))?;
662                }
663                if let Some(position) = column_position {
664                    write!(f, " {position}")?;
665                }
666
667                Ok(())
668            }
669            AlterTableOperation::RenameConstraint { old_name, new_name } => {
670                write!(f, "RENAME CONSTRAINT {old_name} TO {new_name}")
671            }
672            AlterTableOperation::SwapWith { table_name } => {
673                write!(f, "SWAP WITH {table_name}")
674            }
675            AlterTableOperation::OwnerTo { new_owner } => {
676                write!(f, "OWNER TO {new_owner}")
677            }
678            AlterTableOperation::SetTblProperties { table_properties } => {
679                write!(
680                    f,
681                    "SET TBLPROPERTIES({})",
682                    display_comma_separated(table_properties)
683                )
684            }
685            AlterTableOperation::FreezePartition {
686                partition,
687                with_name,
688            } => {
689                write!(f, "FREEZE {partition}")?;
690                if let Some(name) = with_name {
691                    write!(f, " WITH NAME {name}")?;
692                }
693                Ok(())
694            }
695            AlterTableOperation::UnfreezePartition {
696                partition,
697                with_name,
698            } => {
699                write!(f, "UNFREEZE {partition}")?;
700                if let Some(name) = with_name {
701                    write!(f, " WITH NAME {name}")?;
702                }
703                Ok(())
704            }
705            AlterTableOperation::ClusterBy { exprs } => {
706                write!(f, "CLUSTER BY ({})", display_comma_separated(exprs))?;
707                Ok(())
708            }
709            AlterTableOperation::DropClusteringKey => {
710                write!(f, "DROP CLUSTERING KEY")?;
711                Ok(())
712            }
713            AlterTableOperation::SuspendRecluster => {
714                write!(f, "SUSPEND RECLUSTER")?;
715                Ok(())
716            }
717            AlterTableOperation::ResumeRecluster => {
718                write!(f, "RESUME RECLUSTER")?;
719                Ok(())
720            }
721            AlterTableOperation::AutoIncrement { equals, value } => {
722                write!(
723                    f,
724                    "AUTO_INCREMENT {}{}",
725                    if *equals { "= " } else { "" },
726                    value
727                )
728            }
729            AlterTableOperation::Lock { equals, lock } => {
730                write!(f, "LOCK {}{}", if *equals { "= " } else { "" }, lock)
731            }
732        }
733    }
734}
735
736impl fmt::Display for AlterIndexOperation {
737    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
738        match self {
739            AlterIndexOperation::RenameIndex { index_name } => {
740                write!(f, "RENAME TO {index_name}")
741            }
742        }
743    }
744}
745
746/// An `ALTER TYPE` statement (`Statement::AlterType`)
747#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
748#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
749#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
750pub struct AlterType {
751    pub name: ObjectName,
752    pub operation: AlterTypeOperation,
753}
754
755/// An [AlterType] operation
756#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
757#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
758#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
759pub enum AlterTypeOperation {
760    Rename(AlterTypeRename),
761    AddValue(AlterTypeAddValue),
762    RenameValue(AlterTypeRenameValue),
763}
764
765/// See [AlterTypeOperation::Rename]
766#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
767#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
768#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
769pub struct AlterTypeRename {
770    pub new_name: Ident,
771}
772
773/// See [AlterTypeOperation::AddValue]
774#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
775#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
776#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
777pub struct AlterTypeAddValue {
778    pub if_not_exists: bool,
779    pub value: Ident,
780    pub position: Option<AlterTypeAddValuePosition>,
781}
782
783/// See [AlterTypeAddValue]
784#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
785#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
786#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
787pub enum AlterTypeAddValuePosition {
788    Before(Ident),
789    After(Ident),
790}
791
792/// See [AlterTypeOperation::RenameValue]
793#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
794#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
795#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
796pub struct AlterTypeRenameValue {
797    pub from: Ident,
798    pub to: Ident,
799}
800
801impl fmt::Display for AlterTypeOperation {
802    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
803        match self {
804            Self::Rename(AlterTypeRename { new_name }) => {
805                write!(f, "RENAME TO {new_name}")
806            }
807            Self::AddValue(AlterTypeAddValue {
808                if_not_exists,
809                value,
810                position,
811            }) => {
812                write!(f, "ADD VALUE")?;
813                if *if_not_exists {
814                    write!(f, " IF NOT EXISTS")?;
815                }
816                write!(f, " {value}")?;
817                match position {
818                    Some(AlterTypeAddValuePosition::Before(neighbor_value)) => {
819                        write!(f, " BEFORE {neighbor_value}")?;
820                    }
821                    Some(AlterTypeAddValuePosition::After(neighbor_value)) => {
822                        write!(f, " AFTER {neighbor_value}")?;
823                    }
824                    None => {}
825                };
826                Ok(())
827            }
828            Self::RenameValue(AlterTypeRenameValue { from, to }) => {
829                write!(f, "RENAME VALUE {from} TO {to}")
830            }
831        }
832    }
833}
834
835/// An `ALTER COLUMN` (`Statement::AlterTable`) operation
836#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
837#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
838#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
839pub enum AlterColumnOperation {
840    /// `SET NOT NULL`
841    SetNotNull,
842    /// `DROP NOT NULL`
843    DropNotNull,
844    /// `SET DEFAULT <expr>`
845    SetDefault { value: Expr },
846    /// `DROP DEFAULT`
847    DropDefault,
848    /// `[SET DATA] TYPE <data_type> [USING <expr>]`
849    SetDataType {
850        data_type: DataType,
851        /// PostgreSQL specific
852        using: Option<Expr>,
853    },
854    /// `ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]`
855    ///
856    /// Note: this is a PostgreSQL-specific operation.
857    AddGenerated {
858        generated_as: Option<GeneratedAs>,
859        sequence_options: Option<Vec<SequenceOptions>>,
860    },
861}
862
863impl fmt::Display for AlterColumnOperation {
864    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
865        match self {
866            AlterColumnOperation::SetNotNull => write!(f, "SET NOT NULL",),
867            AlterColumnOperation::DropNotNull => write!(f, "DROP NOT NULL",),
868            AlterColumnOperation::SetDefault { value } => {
869                write!(f, "SET DEFAULT {value}")
870            }
871            AlterColumnOperation::DropDefault => {
872                write!(f, "DROP DEFAULT")
873            }
874            AlterColumnOperation::SetDataType { data_type, using } => {
875                if let Some(expr) = using {
876                    write!(f, "SET DATA TYPE {data_type} USING {expr}")
877                } else {
878                    write!(f, "SET DATA TYPE {data_type}")
879                }
880            }
881            AlterColumnOperation::AddGenerated {
882                generated_as,
883                sequence_options,
884            } => {
885                let generated_as = match generated_as {
886                    Some(GeneratedAs::Always) => " ALWAYS",
887                    Some(GeneratedAs::ByDefault) => " BY DEFAULT",
888                    _ => "",
889                };
890
891                write!(f, "ADD GENERATED{generated_as} AS IDENTITY",)?;
892                if let Some(options) = sequence_options {
893                    write!(f, " (")?;
894
895                    for sequence_option in options {
896                        write!(f, "{sequence_option}")?;
897                    }
898
899                    write!(f, " )")?;
900                }
901                Ok(())
902            }
903        }
904    }
905}
906
907/// A table-level constraint, specified in a `CREATE TABLE` or an
908/// `ALTER TABLE ADD <constraint>` statement.
909#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
910#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
911#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
912pub enum TableConstraint {
913    /// MySQL [definition][1] for `UNIQUE` constraints statements:\
914    /// * `[CONSTRAINT [<name>]] UNIQUE <index_type_display> [<index_name>] [index_type] (<columns>) <index_options>`
915    ///
916    /// where:
917    /// * [index_type][2] is `USING {BTREE | HASH}`
918    /// * [index_options][3] is `{index_type | COMMENT 'string' | ... %currently unsupported stmts% } ...`
919    /// * [index_type_display][4] is `[INDEX | KEY]`
920    ///
921    /// [1]: https://dev.mysql.com/doc/refman/8.3/en/create-table.html
922    /// [2]: IndexType
923    /// [3]: IndexOption
924    /// [4]: KeyOrIndexDisplay
925    Unique {
926        /// Constraint name.
927        ///
928        /// Can be not the same as `index_name`
929        name: Option<Ident>,
930        /// Index name
931        index_name: Option<Ident>,
932        /// Whether the type is followed by the keyword `KEY`, `INDEX`, or no keyword at all.
933        index_type_display: KeyOrIndexDisplay,
934        /// Optional `USING` of [index type][1] statement before columns.
935        ///
936        /// [1]: IndexType
937        index_type: Option<IndexType>,
938        /// Identifiers of the columns that are unique.
939        columns: Vec<Ident>,
940        index_options: Vec<IndexOption>,
941        characteristics: Option<ConstraintCharacteristics>,
942        /// Optional Postgres nulls handling: `[ NULLS [ NOT ] DISTINCT ]`
943        nulls_distinct: NullsDistinctOption,
944    },
945    /// MySQL [definition][1] for `PRIMARY KEY` constraints statements:\
946    /// * `[CONSTRAINT [<name>]] PRIMARY KEY [index_name] [index_type] (<columns>) <index_options>`
947    ///
948    /// Actually the specification have no `[index_name]` but the next query will complete successfully:
949    /// ```sql
950    /// CREATE TABLE unspec_table (
951    ///   xid INT NOT NULL,
952    ///   CONSTRAINT p_name PRIMARY KEY index_name USING BTREE (xid)
953    /// );
954    /// ```
955    ///
956    /// where:
957    /// * [index_type][2] is `USING {BTREE | HASH}`
958    /// * [index_options][3] is `{index_type | COMMENT 'string' | ... %currently unsupported stmts% } ...`
959    ///
960    /// [1]: https://dev.mysql.com/doc/refman/8.3/en/create-table.html
961    /// [2]: IndexType
962    /// [3]: IndexOption
963    PrimaryKey {
964        /// Constraint name.
965        ///
966        /// Can be not the same as `index_name`
967        name: Option<Ident>,
968        /// Index name
969        index_name: Option<Ident>,
970        /// Optional `USING` of [index type][1] statement before columns.
971        ///
972        /// [1]: IndexType
973        index_type: Option<IndexType>,
974        /// Identifiers of the columns that form the primary key.
975        columns: Vec<Ident>,
976        index_options: Vec<IndexOption>,
977        characteristics: Option<ConstraintCharacteristics>,
978    },
979    /// A referential integrity constraint (`[ CONSTRAINT <name> ] FOREIGN KEY (<columns>)
980    /// REFERENCES <foreign_table> (<referred_columns>)
981    /// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
982    ///   [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
983    /// }`).
984    ForeignKey {
985        name: Option<Ident>,
986        columns: Vec<Ident>,
987        foreign_table: ObjectName,
988        referred_columns: Vec<Ident>,
989        on_delete: Option<ReferentialAction>,
990        on_update: Option<ReferentialAction>,
991        characteristics: Option<ConstraintCharacteristics>,
992    },
993    /// `[ CONSTRAINT <name> ] CHECK (<expr>)`
994    Check {
995        name: Option<Ident>,
996        expr: Box<Expr>,
997    },
998    /// MySQLs [index definition][1] for index creation. Not present on ANSI so, for now, the usage
999    /// is restricted to MySQL, as no other dialects that support this syntax were found.
1000    ///
1001    /// `{INDEX | KEY} [index_name] [index_type] (key_part,...) [index_option]...`
1002    ///
1003    /// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1004    Index {
1005        /// Whether this index starts with KEY (true) or INDEX (false), to maintain the same syntax.
1006        display_as_key: bool,
1007        /// Index name.
1008        name: Option<Ident>,
1009        /// Optional [index type][1].
1010        ///
1011        /// [1]: IndexType
1012        index_type: Option<IndexType>,
1013        /// Referred column identifier list.
1014        columns: Vec<Ident>,
1015    },
1016    /// MySQLs [fulltext][1] definition. Since the [`SPATIAL`][2] definition is exactly the same,
1017    /// and MySQL displays both the same way, it is part of this definition as well.
1018    ///
1019    /// Supported syntax:
1020    ///
1021    /// ```markdown
1022    /// {FULLTEXT | SPATIAL} [INDEX | KEY] [index_name] (key_part,...)
1023    ///
1024    /// key_part: col_name
1025    /// ```
1026    ///
1027    /// [1]: https://dev.mysql.com/doc/refman/8.0/en/fulltext-natural-language.html
1028    /// [2]: https://dev.mysql.com/doc/refman/8.0/en/spatial-types.html
1029    FulltextOrSpatial {
1030        /// Whether this is a `FULLTEXT` (true) or `SPATIAL` (false) definition.
1031        fulltext: bool,
1032        /// Whether the type is followed by the keyword `KEY`, `INDEX`, or no keyword at all.
1033        index_type_display: KeyOrIndexDisplay,
1034        /// Optional index name.
1035        opt_index_name: Option<Ident>,
1036        /// Referred column identifier list.
1037        columns: Vec<Ident>,
1038    },
1039}
1040
1041impl fmt::Display for TableConstraint {
1042    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1043        match self {
1044            TableConstraint::Unique {
1045                name,
1046                index_name,
1047                index_type_display,
1048                index_type,
1049                columns,
1050                index_options,
1051                characteristics,
1052                nulls_distinct,
1053            } => {
1054                write!(
1055                    f,
1056                    "{}UNIQUE{nulls_distinct}{index_type_display:>}{}{} ({})",
1057                    display_constraint_name(name),
1058                    display_option_spaced(index_name),
1059                    display_option(" USING ", "", index_type),
1060                    display_comma_separated(columns),
1061                )?;
1062
1063                if !index_options.is_empty() {
1064                    write!(f, " {}", display_separated(index_options, " "))?;
1065                }
1066
1067                write!(f, "{}", display_option_spaced(characteristics))?;
1068                Ok(())
1069            }
1070            TableConstraint::PrimaryKey {
1071                name,
1072                index_name,
1073                index_type,
1074                columns,
1075                index_options,
1076                characteristics,
1077            } => {
1078                write!(
1079                    f,
1080                    "{}PRIMARY KEY{}{} ({})",
1081                    display_constraint_name(name),
1082                    display_option_spaced(index_name),
1083                    display_option(" USING ", "", index_type),
1084                    display_comma_separated(columns),
1085                )?;
1086
1087                if !index_options.is_empty() {
1088                    write!(f, " {}", display_separated(index_options, " "))?;
1089                }
1090
1091                write!(f, "{}", display_option_spaced(characteristics))?;
1092                Ok(())
1093            }
1094            TableConstraint::ForeignKey {
1095                name,
1096                columns,
1097                foreign_table,
1098                referred_columns,
1099                on_delete,
1100                on_update,
1101                characteristics,
1102            } => {
1103                write!(
1104                    f,
1105                    "{}FOREIGN KEY ({}) REFERENCES {}",
1106                    display_constraint_name(name),
1107                    display_comma_separated(columns),
1108                    foreign_table,
1109                )?;
1110                if !referred_columns.is_empty() {
1111                    write!(f, "({})", display_comma_separated(referred_columns))?;
1112                }
1113                if let Some(action) = on_delete {
1114                    write!(f, " ON DELETE {action}")?;
1115                }
1116                if let Some(action) = on_update {
1117                    write!(f, " ON UPDATE {action}")?;
1118                }
1119                if let Some(characteristics) = characteristics {
1120                    write!(f, " {}", characteristics)?;
1121                }
1122                Ok(())
1123            }
1124            TableConstraint::Check { name, expr } => {
1125                write!(f, "{}CHECK ({})", display_constraint_name(name), expr)
1126            }
1127            TableConstraint::Index {
1128                display_as_key,
1129                name,
1130                index_type,
1131                columns,
1132            } => {
1133                write!(f, "{}", if *display_as_key { "KEY" } else { "INDEX" })?;
1134                if let Some(name) = name {
1135                    write!(f, " {name}")?;
1136                }
1137                if let Some(index_type) = index_type {
1138                    write!(f, " USING {index_type}")?;
1139                }
1140                write!(f, " ({})", display_comma_separated(columns))?;
1141
1142                Ok(())
1143            }
1144            Self::FulltextOrSpatial {
1145                fulltext,
1146                index_type_display,
1147                opt_index_name,
1148                columns,
1149            } => {
1150                if *fulltext {
1151                    write!(f, "FULLTEXT")?;
1152                } else {
1153                    write!(f, "SPATIAL")?;
1154                }
1155
1156                write!(f, "{index_type_display:>}")?;
1157
1158                if let Some(name) = opt_index_name {
1159                    write!(f, " {name}")?;
1160                }
1161
1162                write!(f, " ({})", display_comma_separated(columns))?;
1163
1164                Ok(())
1165            }
1166        }
1167    }
1168}
1169
1170/// Representation whether a definition can can contains the KEY or INDEX keywords with the same
1171/// meaning.
1172///
1173/// This enum initially is directed to `FULLTEXT`,`SPATIAL`, and `UNIQUE` indexes on create table
1174/// statements of `MySQL` [(1)].
1175///
1176/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1177#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1178#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1179#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1180pub enum KeyOrIndexDisplay {
1181    /// Nothing to display
1182    None,
1183    /// Display the KEY keyword
1184    Key,
1185    /// Display the INDEX keyword
1186    Index,
1187}
1188
1189impl KeyOrIndexDisplay {
1190    pub fn is_none(self) -> bool {
1191        matches!(self, Self::None)
1192    }
1193}
1194
1195impl fmt::Display for KeyOrIndexDisplay {
1196    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1197        let left_space = matches!(f.align(), Some(fmt::Alignment::Right));
1198
1199        if left_space && !self.is_none() {
1200            f.write_char(' ')?
1201        }
1202
1203        match self {
1204            KeyOrIndexDisplay::None => {
1205                write!(f, "")
1206            }
1207            KeyOrIndexDisplay::Key => {
1208                write!(f, "KEY")
1209            }
1210            KeyOrIndexDisplay::Index => {
1211                write!(f, "INDEX")
1212            }
1213        }
1214    }
1215}
1216
1217/// Indexing method used by that index.
1218///
1219/// This structure isn't present on ANSI, but is found at least in [`MySQL` CREATE TABLE][1],
1220/// [`MySQL` CREATE INDEX][2], and [Postgresql CREATE INDEX][3] statements.
1221///
1222/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
1223/// [2]: https://dev.mysql.com/doc/refman/8.0/en/create-index.html
1224/// [3]: https://www.postgresql.org/docs/14/sql-createindex.html
1225#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1226#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1227#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1228pub enum IndexType {
1229    BTree,
1230    Hash,
1231    GIN,
1232    GiST,
1233    SPGiST,
1234    BRIN,
1235    Bloom,
1236    /// Users may define their own index types, which would
1237    /// not be covered by the above variants.
1238    Custom(Ident),
1239}
1240
1241impl fmt::Display for IndexType {
1242    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1243        match self {
1244            Self::BTree => write!(f, "BTREE"),
1245            Self::Hash => write!(f, "HASH"),
1246            Self::GIN => write!(f, "GIN"),
1247            Self::GiST => write!(f, "GIST"),
1248            Self::SPGiST => write!(f, "SPGIST"),
1249            Self::BRIN => write!(f, "BRIN"),
1250            Self::Bloom => write!(f, "BLOOM"),
1251            Self::Custom(name) => write!(f, "{}", name),
1252        }
1253    }
1254}
1255
1256/// MySQLs index option.
1257///
1258/// This structure used here [`MySQL` CREATE TABLE][1], [`MySQL` CREATE INDEX][2].
1259///
1260/// [1]: https://dev.mysql.com/doc/refman/8.3/en/create-table.html
1261/// [2]: https://dev.mysql.com/doc/refman/8.3/en/create-index.html
1262#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1263#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1264#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1265pub enum IndexOption {
1266    Using(IndexType),
1267    Comment(String),
1268}
1269
1270impl fmt::Display for IndexOption {
1271    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1272        match self {
1273            Self::Using(index_type) => write!(f, "USING {index_type}"),
1274            Self::Comment(s) => write!(f, "COMMENT '{s}'"),
1275        }
1276    }
1277}
1278
1279/// [PostgreSQL] unique index nulls handling option: `[ NULLS [ NOT ] DISTINCT ]`
1280///
1281/// [PostgreSQL]: https://www.postgresql.org/docs/17/sql-altertable.html
1282#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1283#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1284#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1285pub enum NullsDistinctOption {
1286    /// Not specified
1287    None,
1288    /// NULLS DISTINCT
1289    Distinct,
1290    /// NULLS NOT DISTINCT
1291    NotDistinct,
1292}
1293
1294impl fmt::Display for NullsDistinctOption {
1295    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1296        match self {
1297            Self::None => Ok(()),
1298            Self::Distinct => write!(f, " NULLS DISTINCT"),
1299            Self::NotDistinct => write!(f, " NULLS NOT DISTINCT"),
1300        }
1301    }
1302}
1303
1304#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1305#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1306#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1307pub struct ProcedureParam {
1308    pub name: Ident,
1309    pub data_type: DataType,
1310}
1311
1312impl fmt::Display for ProcedureParam {
1313    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1314        write!(f, "{} {}", self.name, self.data_type)
1315    }
1316}
1317
1318/// SQL column definition
1319#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1320#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1321#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1322pub struct ColumnDef {
1323    pub name: Ident,
1324    pub data_type: DataType,
1325    pub options: Vec<ColumnOptionDef>,
1326}
1327
1328impl fmt::Display for ColumnDef {
1329    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1330        if self.data_type == DataType::Unspecified {
1331            write!(f, "{}", self.name)?;
1332        } else {
1333            write!(f, "{} {}", self.name, self.data_type)?;
1334        }
1335        for option in &self.options {
1336            write!(f, " {option}")?;
1337        }
1338        Ok(())
1339    }
1340}
1341
1342/// Column definition specified in a `CREATE VIEW` statement.
1343///
1344/// Syntax
1345/// ```markdown
1346/// <name> [data_type][OPTIONS(option, ...)]
1347///
1348/// option: <name> = <value>
1349/// ```
1350///
1351/// Examples:
1352/// ```sql
1353/// name
1354/// age OPTIONS(description = "age column", tag = "prod")
1355/// amount COMMENT 'The total amount for the order line'
1356/// created_at DateTime64
1357/// ```
1358#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1359#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1360#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1361pub struct ViewColumnDef {
1362    pub name: Ident,
1363    pub data_type: Option<DataType>,
1364    pub options: Option<Vec<ColumnOption>>,
1365}
1366
1367impl fmt::Display for ViewColumnDef {
1368    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1369        write!(f, "{}", self.name)?;
1370        if let Some(data_type) = self.data_type.as_ref() {
1371            write!(f, " {}", data_type)?;
1372        }
1373        if let Some(options) = self.options.as_ref() {
1374            write!(f, " {}", display_comma_separated(options.as_slice()))?;
1375        }
1376        Ok(())
1377    }
1378}
1379
1380/// An optionally-named `ColumnOption`: `[ CONSTRAINT <name> ] <column-option>`.
1381///
1382/// Note that implementations are substantially more permissive than the ANSI
1383/// specification on what order column options can be presented in, and whether
1384/// they are allowed to be named. The specification distinguishes between
1385/// constraints (NOT NULL, UNIQUE, PRIMARY KEY, and CHECK), which can be named
1386/// and can appear in any order, and other options (DEFAULT, GENERATED), which
1387/// cannot be named and must appear in a fixed order. `PostgreSQL`, however,
1388/// allows preceding any option with `CONSTRAINT <name>`, even those that are
1389/// not really constraints, like NULL and DEFAULT. MSSQL is less permissive,
1390/// allowing DEFAULT, UNIQUE, PRIMARY KEY and CHECK to be named, but not NULL or
1391/// NOT NULL constraints (the last of which is in violation of the spec).
1392///
1393/// For maximum flexibility, we don't distinguish between constraint and
1394/// non-constraint options, lumping them all together under the umbrella of
1395/// "column options," and we allow any column option to be named.
1396#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1397#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1398#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1399pub struct ColumnOptionDef {
1400    pub name: Option<Ident>,
1401    pub option: ColumnOption,
1402}
1403
1404impl fmt::Display for ColumnOptionDef {
1405    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1406        write!(f, "{}{}", display_constraint_name(&self.name), self.option)
1407    }
1408}
1409
1410/// Identity is a column option for defining an identity or autoincrement column in a `CREATE TABLE` statement.
1411/// Syntax
1412/// ```sql
1413/// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1414/// ```
1415/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1416/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1417#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1418#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1419#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1420pub enum IdentityPropertyKind {
1421    /// An identity property declared via the `AUTOINCREMENT` key word
1422    /// Example:
1423    /// ```sql
1424    ///  AUTOINCREMENT(100, 1) NOORDER
1425    ///  AUTOINCREMENT START 100 INCREMENT 1 ORDER
1426    /// ```
1427    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1428    Autoincrement(IdentityProperty),
1429    /// An identity property declared via the `IDENTITY` key word
1430    /// Example, [MS SQL Server] or [Snowflake]:
1431    /// ```sql
1432    ///  IDENTITY(100, 1)
1433    /// ```
1434    /// [Snowflake]
1435    /// ```sql
1436    ///  IDENTITY(100, 1) ORDER
1437    ///  IDENTITY START 100 INCREMENT 1 NOORDER
1438    /// ```
1439    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1440    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1441    Identity(IdentityProperty),
1442}
1443
1444impl fmt::Display for IdentityPropertyKind {
1445    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1446        let (command, property) = match self {
1447            IdentityPropertyKind::Identity(property) => ("IDENTITY", property),
1448            IdentityPropertyKind::Autoincrement(property) => ("AUTOINCREMENT", property),
1449        };
1450        write!(f, "{command}")?;
1451        if let Some(parameters) = &property.parameters {
1452            write!(f, "{parameters}")?;
1453        }
1454        if let Some(order) = &property.order {
1455            write!(f, "{order}")?;
1456        }
1457        Ok(())
1458    }
1459}
1460
1461#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1462#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1463#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1464pub struct IdentityProperty {
1465    pub parameters: Option<IdentityPropertyFormatKind>,
1466    pub order: Option<IdentityPropertyOrder>,
1467}
1468
1469/// A format of parameters of identity column.
1470///
1471/// It is [Snowflake] specific.
1472/// Syntax
1473/// ```sql
1474/// (seed , increment) | START num INCREMENT num
1475/// ```
1476/// [MS SQL Server] uses one way of representing these parameters.
1477/// Syntax
1478/// ```sql
1479/// (seed , increment)
1480/// ```
1481/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1482/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1483#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1484#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1485#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1486pub enum IdentityPropertyFormatKind {
1487    /// A parameters of identity column declared like parameters of function call
1488    /// Example:
1489    /// ```sql
1490    ///  (100, 1)
1491    /// ```
1492    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1493    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1494    FunctionCall(IdentityParameters),
1495    /// A parameters of identity column declared with keywords `START` and `INCREMENT`
1496    /// Example:
1497    /// ```sql
1498    ///  START 100 INCREMENT 1
1499    /// ```
1500    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1501    StartAndIncrement(IdentityParameters),
1502}
1503
1504impl fmt::Display for IdentityPropertyFormatKind {
1505    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1506        match self {
1507            IdentityPropertyFormatKind::FunctionCall(parameters) => {
1508                write!(f, "({}, {})", parameters.seed, parameters.increment)
1509            }
1510            IdentityPropertyFormatKind::StartAndIncrement(parameters) => {
1511                write!(
1512                    f,
1513                    " START {} INCREMENT {}",
1514                    parameters.seed, parameters.increment
1515                )
1516            }
1517        }
1518    }
1519}
1520#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1521#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1522#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1523pub struct IdentityParameters {
1524    pub seed: Expr,
1525    pub increment: Expr,
1526}
1527
1528/// The identity column option specifies how values are generated for the auto-incremented column, either in increasing or decreasing order.
1529/// Syntax
1530/// ```sql
1531/// ORDER | NOORDER
1532/// ```
1533/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1534#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1535#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1536#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1537pub enum IdentityPropertyOrder {
1538    Order,
1539    NoOrder,
1540}
1541
1542impl fmt::Display for IdentityPropertyOrder {
1543    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1544        match self {
1545            IdentityPropertyOrder::Order => write!(f, " ORDER"),
1546            IdentityPropertyOrder::NoOrder => write!(f, " NOORDER"),
1547        }
1548    }
1549}
1550
1551/// Column policy that identify a security policy of access to a column.
1552/// Syntax
1553/// ```sql
1554/// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1555/// [ WITH ] PROJECTION POLICY <policy_name>
1556/// ```
1557/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1558#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1559#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1560#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1561pub enum ColumnPolicy {
1562    MaskingPolicy(ColumnPolicyProperty),
1563    ProjectionPolicy(ColumnPolicyProperty),
1564}
1565
1566impl fmt::Display for ColumnPolicy {
1567    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1568        let (command, property) = match self {
1569            ColumnPolicy::MaskingPolicy(property) => ("MASKING POLICY", property),
1570            ColumnPolicy::ProjectionPolicy(property) => ("PROJECTION POLICY", property),
1571        };
1572        if property.with {
1573            write!(f, "WITH ")?;
1574        }
1575        write!(f, "{command} {}", property.policy_name)?;
1576        if let Some(using_columns) = &property.using_columns {
1577            write!(f, " USING ({})", display_comma_separated(using_columns))?;
1578        }
1579        Ok(())
1580    }
1581}
1582
1583#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1584#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1585#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1586pub struct ColumnPolicyProperty {
1587    /// This flag indicates that the column policy option is declared using the `WITH` prefix.
1588    /// Example
1589    /// ```sql
1590    /// WITH PROJECTION POLICY sample_policy
1591    /// ```
1592    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1593    pub with: bool,
1594    pub policy_name: Ident,
1595    pub using_columns: Option<Vec<Ident>>,
1596}
1597
1598/// Tags option of column
1599/// Syntax
1600/// ```sql
1601/// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1602/// ```
1603/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1604#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1605#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1606#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1607pub struct TagsColumnOption {
1608    /// This flag indicates that the tags option is declared using the `WITH` prefix.
1609    /// Example:
1610    /// ```sql
1611    /// WITH TAG (A = 'Tag A')
1612    /// ```
1613    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1614    pub with: bool,
1615    pub tags: Vec<Tag>,
1616}
1617
1618impl fmt::Display for TagsColumnOption {
1619    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1620        if self.with {
1621            write!(f, "WITH ")?;
1622        }
1623        write!(f, "TAG ({})", display_comma_separated(&self.tags))?;
1624        Ok(())
1625    }
1626}
1627
1628/// `ColumnOption`s are modifiers that follow a column definition in a `CREATE
1629/// TABLE` statement.
1630#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1631#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1632#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1633pub enum ColumnOption {
1634    /// `NULL`
1635    Null,
1636    /// `NOT NULL`
1637    NotNull,
1638    /// `DEFAULT <restricted-expr>`
1639    Default(Expr),
1640
1641    /// `MATERIALIZE <expr>`
1642    /// Syntax: `b INT MATERIALIZE (a + 1)`
1643    ///
1644    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1645    Materialized(Expr),
1646    /// `EPHEMERAL [<expr>]`
1647    ///
1648    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1649    Ephemeral(Option<Expr>),
1650    /// `ALIAS <expr>`
1651    ///
1652    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
1653    Alias(Expr),
1654
1655    /// `{ PRIMARY KEY | UNIQUE } [<constraint_characteristics>]`
1656    Unique {
1657        is_primary: bool,
1658        characteristics: Option<ConstraintCharacteristics>,
1659    },
1660    /// A referential integrity constraint (`[FOREIGN KEY REFERENCES
1661    /// <foreign_table> (<referred_columns>)
1662    /// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
1663    ///   [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
1664    /// }
1665    /// [<constraint_characteristics>]
1666    /// `).
1667    ForeignKey {
1668        foreign_table: ObjectName,
1669        referred_columns: Vec<Ident>,
1670        on_delete: Option<ReferentialAction>,
1671        on_update: Option<ReferentialAction>,
1672        characteristics: Option<ConstraintCharacteristics>,
1673    },
1674    /// `CHECK (<expr>)`
1675    Check(Expr),
1676    /// Dialect-specific options, such as:
1677    /// - MySQL's `AUTO_INCREMENT` or SQLite's `AUTOINCREMENT`
1678    /// - ...
1679    DialectSpecific(Vec<Token>),
1680    CharacterSet(ObjectName),
1681    Collation(ObjectName),
1682    Comment(String),
1683    OnUpdate(Expr),
1684    /// `Generated`s are modifiers that follow a column definition in a `CREATE
1685    /// TABLE` statement.
1686    Generated {
1687        generated_as: GeneratedAs,
1688        sequence_options: Option<Vec<SequenceOptions>>,
1689        generation_expr: Option<Expr>,
1690        generation_expr_mode: Option<GeneratedExpressionMode>,
1691        /// false if 'GENERATED ALWAYS' is skipped (option starts with AS)
1692        generated_keyword: bool,
1693    },
1694    /// BigQuery specific: Explicit column options in a view [1] or table [2]
1695    /// Syntax
1696    /// ```sql
1697    /// OPTIONS(description="field desc")
1698    /// ```
1699    /// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#view_column_option_list
1700    /// [2]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#column_option_list
1701    Options(Vec<SqlOption>),
1702    /// Creates an identity or an autoincrement column in a table.
1703    /// Syntax
1704    /// ```sql
1705    /// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1706    /// ```
1707    /// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1708    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1709    Identity(IdentityPropertyKind),
1710    /// SQLite specific: ON CONFLICT option on column definition
1711    /// <https://www.sqlite.org/lang_conflict.html>
1712    OnConflict(Keyword),
1713    /// Snowflake specific: an option of specifying security masking or projection policy to set on a column.
1714    /// Syntax:
1715    /// ```sql
1716    /// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1717    /// [ WITH ] PROJECTION POLICY <policy_name>
1718    /// ```
1719    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1720    Policy(ColumnPolicy),
1721    /// Snowflake specific: Specifies the tag name and the tag string value.
1722    /// Syntax:
1723    /// ```sql
1724    /// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1725    /// ```
1726    /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1727    Tags(TagsColumnOption),
1728}
1729
1730impl fmt::Display for ColumnOption {
1731    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1732        use ColumnOption::*;
1733        match self {
1734            Null => write!(f, "NULL"),
1735            NotNull => write!(f, "NOT NULL"),
1736            Default(expr) => write!(f, "DEFAULT {expr}"),
1737            Materialized(expr) => write!(f, "MATERIALIZED {expr}"),
1738            Ephemeral(expr) => {
1739                if let Some(e) = expr {
1740                    write!(f, "EPHEMERAL {e}")
1741                } else {
1742                    write!(f, "EPHEMERAL")
1743                }
1744            }
1745            Alias(expr) => write!(f, "ALIAS {expr}"),
1746            Unique {
1747                is_primary,
1748                characteristics,
1749            } => {
1750                write!(f, "{}", if *is_primary { "PRIMARY KEY" } else { "UNIQUE" })?;
1751                if let Some(characteristics) = characteristics {
1752                    write!(f, " {}", characteristics)?;
1753                }
1754                Ok(())
1755            }
1756            ForeignKey {
1757                foreign_table,
1758                referred_columns,
1759                on_delete,
1760                on_update,
1761                characteristics,
1762            } => {
1763                write!(f, "REFERENCES {foreign_table}")?;
1764                if !referred_columns.is_empty() {
1765                    write!(f, " ({})", display_comma_separated(referred_columns))?;
1766                }
1767                if let Some(action) = on_delete {
1768                    write!(f, " ON DELETE {action}")?;
1769                }
1770                if let Some(action) = on_update {
1771                    write!(f, " ON UPDATE {action}")?;
1772                }
1773                if let Some(characteristics) = characteristics {
1774                    write!(f, " {}", characteristics)?;
1775                }
1776                Ok(())
1777            }
1778            Check(expr) => write!(f, "CHECK ({expr})"),
1779            DialectSpecific(val) => write!(f, "{}", display_separated(val, " ")),
1780            CharacterSet(n) => write!(f, "CHARACTER SET {n}"),
1781            Collation(n) => write!(f, "COLLATE {n}"),
1782            Comment(v) => write!(f, "COMMENT '{}'", escape_single_quote_string(v)),
1783            OnUpdate(expr) => write!(f, "ON UPDATE {expr}"),
1784            Generated {
1785                generated_as,
1786                sequence_options,
1787                generation_expr,
1788                generation_expr_mode,
1789                generated_keyword,
1790            } => {
1791                if let Some(expr) = generation_expr {
1792                    let modifier = match generation_expr_mode {
1793                        None => "",
1794                        Some(GeneratedExpressionMode::Virtual) => " VIRTUAL",
1795                        Some(GeneratedExpressionMode::Stored) => " STORED",
1796                    };
1797                    if *generated_keyword {
1798                        write!(f, "GENERATED ALWAYS AS ({expr}){modifier}")?;
1799                    } else {
1800                        write!(f, "AS ({expr}){modifier}")?;
1801                    }
1802                    Ok(())
1803                } else {
1804                    // Like Postgres - generated from sequence
1805                    let when = match generated_as {
1806                        GeneratedAs::Always => "ALWAYS",
1807                        GeneratedAs::ByDefault => "BY DEFAULT",
1808                        // ExpStored goes with an expression, handled above
1809                        GeneratedAs::ExpStored => unreachable!(),
1810                    };
1811                    write!(f, "GENERATED {when} AS IDENTITY")?;
1812                    if sequence_options.is_some() {
1813                        let so = sequence_options.as_ref().unwrap();
1814                        if !so.is_empty() {
1815                            write!(f, " (")?;
1816                        }
1817                        for sequence_option in so {
1818                            write!(f, "{sequence_option}")?;
1819                        }
1820                        if !so.is_empty() {
1821                            write!(f, " )")?;
1822                        }
1823                    }
1824                    Ok(())
1825                }
1826            }
1827            Options(options) => {
1828                write!(f, "OPTIONS({})", display_comma_separated(options))
1829            }
1830            Identity(parameters) => {
1831                write!(f, "{parameters}")
1832            }
1833            OnConflict(keyword) => {
1834                write!(f, "ON CONFLICT {:?}", keyword)?;
1835                Ok(())
1836            }
1837            Policy(parameters) => {
1838                write!(f, "{parameters}")
1839            }
1840            Tags(tags) => {
1841                write!(f, "{tags}")
1842            }
1843        }
1844    }
1845}
1846
1847/// `GeneratedAs`s are modifiers that follow a column option in a `generated`.
1848/// 'ExpStored' is used for a column generated from an expression and stored.
1849#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1850#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1851#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1852pub enum GeneratedAs {
1853    Always,
1854    ByDefault,
1855    ExpStored,
1856}
1857
1858/// `GeneratedExpressionMode`s are modifiers that follow an expression in a `generated`.
1859/// No modifier is typically the same as Virtual.
1860#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1861#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1862#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1863pub enum GeneratedExpressionMode {
1864    Virtual,
1865    Stored,
1866}
1867
1868#[must_use]
1869fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
1870    struct ConstraintName<'a>(&'a Option<Ident>);
1871    impl fmt::Display for ConstraintName<'_> {
1872        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1873            if let Some(name) = self.0 {
1874                write!(f, "CONSTRAINT {name} ")?;
1875            }
1876            Ok(())
1877        }
1878    }
1879    ConstraintName(name)
1880}
1881
1882/// If `option` is
1883/// * `Some(inner)` => create display struct for `"{prefix}{inner}{postfix}"`
1884/// * `_` => do nothing
1885#[must_use]
1886fn display_option<'a, T: fmt::Display>(
1887    prefix: &'a str,
1888    postfix: &'a str,
1889    option: &'a Option<T>,
1890) -> impl fmt::Display + 'a {
1891    struct OptionDisplay<'a, T>(&'a str, &'a str, &'a Option<T>);
1892    impl<T: fmt::Display> fmt::Display for OptionDisplay<'_, T> {
1893        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1894            if let Some(inner) = self.2 {
1895                let (prefix, postfix) = (self.0, self.1);
1896                write!(f, "{prefix}{inner}{postfix}")?;
1897            }
1898            Ok(())
1899        }
1900    }
1901    OptionDisplay(prefix, postfix, option)
1902}
1903
1904/// If `option` is
1905/// * `Some(inner)` => create display struct for `" {inner}"`
1906/// * `_` => do nothing
1907#[must_use]
1908fn display_option_spaced<T: fmt::Display>(option: &Option<T>) -> impl fmt::Display + '_ {
1909    display_option(" ", "", option)
1910}
1911
1912/// `<constraint_characteristics> = [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ]`
1913///
1914/// Used in UNIQUE and foreign key constraints. The individual settings may occur in any order.
1915#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Default, Eq, Ord, Hash)]
1916#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1917#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1918pub struct ConstraintCharacteristics {
1919    /// `[ DEFERRABLE | NOT DEFERRABLE ]`
1920    pub deferrable: Option<bool>,
1921    /// `[ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]`
1922    pub initially: Option<DeferrableInitial>,
1923    /// `[ ENFORCED | NOT ENFORCED ]`
1924    pub enforced: Option<bool>,
1925}
1926
1927#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1928#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1929#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1930pub enum DeferrableInitial {
1931    /// `INITIALLY IMMEDIATE`
1932    Immediate,
1933    /// `INITIALLY DEFERRED`
1934    Deferred,
1935}
1936
1937impl ConstraintCharacteristics {
1938    fn deferrable_text(&self) -> Option<&'static str> {
1939        self.deferrable.map(|deferrable| {
1940            if deferrable {
1941                "DEFERRABLE"
1942            } else {
1943                "NOT DEFERRABLE"
1944            }
1945        })
1946    }
1947
1948    fn initially_immediate_text(&self) -> Option<&'static str> {
1949        self.initially
1950            .map(|initially_immediate| match initially_immediate {
1951                DeferrableInitial::Immediate => "INITIALLY IMMEDIATE",
1952                DeferrableInitial::Deferred => "INITIALLY DEFERRED",
1953            })
1954    }
1955
1956    fn enforced_text(&self) -> Option<&'static str> {
1957        self.enforced.map(
1958            |enforced| {
1959                if enforced {
1960                    "ENFORCED"
1961                } else {
1962                    "NOT ENFORCED"
1963                }
1964            },
1965        )
1966    }
1967}
1968
1969impl fmt::Display for ConstraintCharacteristics {
1970    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1971        let deferrable = self.deferrable_text();
1972        let initially_immediate = self.initially_immediate_text();
1973        let enforced = self.enforced_text();
1974
1975        match (deferrable, initially_immediate, enforced) {
1976            (None, None, None) => Ok(()),
1977            (None, None, Some(enforced)) => write!(f, "{enforced}"),
1978            (None, Some(initial), None) => write!(f, "{initial}"),
1979            (None, Some(initial), Some(enforced)) => write!(f, "{initial} {enforced}"),
1980            (Some(deferrable), None, None) => write!(f, "{deferrable}"),
1981            (Some(deferrable), None, Some(enforced)) => write!(f, "{deferrable} {enforced}"),
1982            (Some(deferrable), Some(initial), None) => write!(f, "{deferrable} {initial}"),
1983            (Some(deferrable), Some(initial), Some(enforced)) => {
1984                write!(f, "{deferrable} {initial} {enforced}")
1985            }
1986        }
1987    }
1988}
1989
1990/// `<referential_action> =
1991/// { RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT }`
1992///
1993/// Used in foreign key constraints in `ON UPDATE` and `ON DELETE` options.
1994#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1995#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1996#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1997pub enum ReferentialAction {
1998    Restrict,
1999    Cascade,
2000    SetNull,
2001    NoAction,
2002    SetDefault,
2003}
2004
2005impl fmt::Display for ReferentialAction {
2006    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2007        f.write_str(match self {
2008            ReferentialAction::Restrict => "RESTRICT",
2009            ReferentialAction::Cascade => "CASCADE",
2010            ReferentialAction::SetNull => "SET NULL",
2011            ReferentialAction::NoAction => "NO ACTION",
2012            ReferentialAction::SetDefault => "SET DEFAULT",
2013        })
2014    }
2015}
2016
2017/// `<drop behavior> ::= CASCADE | RESTRICT`.
2018///
2019/// Used in `DROP` statements.
2020#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2021#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2022#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2023pub enum DropBehavior {
2024    Restrict,
2025    Cascade,
2026}
2027
2028impl fmt::Display for DropBehavior {
2029    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2030        f.write_str(match self {
2031            DropBehavior::Restrict => "RESTRICT",
2032            DropBehavior::Cascade => "CASCADE",
2033        })
2034    }
2035}
2036
2037/// SQL user defined type definition
2038#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2039#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2040#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2041pub enum UserDefinedTypeRepresentation {
2042    Composite {
2043        attributes: Vec<UserDefinedTypeCompositeAttributeDef>,
2044    },
2045    /// Note: this is PostgreSQL-specific. See <https://www.postgresql.org/docs/current/sql-createtype.html>
2046    Enum { labels: Vec<Ident> },
2047}
2048
2049impl fmt::Display for UserDefinedTypeRepresentation {
2050    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2051        match self {
2052            UserDefinedTypeRepresentation::Composite { attributes } => {
2053                write!(f, "({})", display_comma_separated(attributes))
2054            }
2055            UserDefinedTypeRepresentation::Enum { labels } => {
2056                write!(f, "ENUM ({})", display_comma_separated(labels))
2057            }
2058        }
2059    }
2060}
2061
2062/// SQL user defined type attribute definition
2063#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2064#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2065#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2066pub struct UserDefinedTypeCompositeAttributeDef {
2067    pub name: Ident,
2068    pub data_type: DataType,
2069    pub collation: Option<ObjectName>,
2070}
2071
2072impl fmt::Display for UserDefinedTypeCompositeAttributeDef {
2073    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2074        write!(f, "{} {}", self.name, self.data_type)?;
2075        if let Some(collation) = &self.collation {
2076            write!(f, " COLLATE {collation}")?;
2077        }
2078        Ok(())
2079    }
2080}
2081
2082/// PARTITION statement used in ALTER TABLE et al. such as in Hive and ClickHouse SQL.
2083/// For example, ClickHouse's OPTIMIZE TABLE supports syntax like PARTITION ID 'partition_id' and PARTITION expr.
2084/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2085#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2086#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2087#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2088pub enum Partition {
2089    Identifier(Ident),
2090    Expr(Expr),
2091    /// ClickHouse supports PART expr which represents physical partition in disk.
2092    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#attach-partitionpart)
2093    Part(Expr),
2094    Partitions(Vec<Expr>),
2095}
2096
2097impl fmt::Display for Partition {
2098    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2099        match self {
2100            Partition::Identifier(id) => write!(f, "PARTITION ID {id}"),
2101            Partition::Expr(expr) => write!(f, "PARTITION {expr}"),
2102            Partition::Part(expr) => write!(f, "PART {expr}"),
2103            Partition::Partitions(partitions) => {
2104                write!(f, "PARTITION ({})", display_comma_separated(partitions))
2105            }
2106        }
2107    }
2108}
2109
2110/// DEDUPLICATE statement used in OPTIMIZE TABLE et al. such as in ClickHouse SQL
2111/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/optimize)
2112#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2113#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2114#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2115pub enum Deduplicate {
2116    All,
2117    ByExpression(Expr),
2118}
2119
2120impl fmt::Display for Deduplicate {
2121    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2122        match self {
2123            Deduplicate::All => write!(f, "DEDUPLICATE"),
2124            Deduplicate::ByExpression(expr) => write!(f, "DEDUPLICATE BY {expr}"),
2125        }
2126    }
2127}
2128
2129/// Hive supports `CLUSTERED BY` statement in `CREATE TABLE`.
2130/// Syntax: `CLUSTERED BY (col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS`
2131///
2132/// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
2133#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2134#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2135#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2136pub struct ClusteredBy {
2137    pub columns: Vec<Ident>,
2138    pub sorted_by: Option<Vec<OrderByExpr>>,
2139    pub num_buckets: Value,
2140}
2141
2142impl fmt::Display for ClusteredBy {
2143    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2144        write!(
2145            f,
2146            "CLUSTERED BY ({})",
2147            display_comma_separated(&self.columns)
2148        )?;
2149        if let Some(ref sorted_by) = self.sorted_by {
2150            write!(f, " SORTED BY ({})", display_comma_separated(sorted_by))?;
2151        }
2152        write!(f, " INTO {} BUCKETS", self.num_buckets)
2153    }
2154}
2155
2156#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2157#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2158#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2159pub struct CreateFunction {
2160    /// True if this is a `CREATE OR ALTER FUNCTION` statement
2161    ///
2162    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql?view=sql-server-ver16#or-alter)
2163    pub or_alter: bool,
2164    pub or_replace: bool,
2165    pub temporary: bool,
2166    pub if_not_exists: bool,
2167    pub name: ObjectName,
2168    pub args: Option<Vec<OperateFunctionArg>>,
2169    pub return_type: Option<DataType>,
2170    /// The expression that defines the function.
2171    ///
2172    /// Examples:
2173    /// ```sql
2174    /// AS ((SELECT 1))
2175    /// AS "console.log();"
2176    /// ```
2177    pub function_body: Option<CreateFunctionBody>,
2178    /// Behavior attribute for the function
2179    ///
2180    /// IMMUTABLE | STABLE | VOLATILE
2181    ///
2182    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
2183    pub behavior: Option<FunctionBehavior>,
2184    /// CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
2185    ///
2186    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
2187    pub called_on_null: Option<FunctionCalledOnNull>,
2188    /// PARALLEL { UNSAFE | RESTRICTED | SAFE }
2189    ///
2190    /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-createfunction.html)
2191    pub parallel: Option<FunctionParallel>,
2192    /// USING ... (Hive only)
2193    pub using: Option<CreateFunctionUsing>,
2194    /// Language used in a UDF definition.
2195    ///
2196    /// Example:
2197    /// ```sql
2198    /// CREATE FUNCTION foo() LANGUAGE js AS "console.log();"
2199    /// ```
2200    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_javascript_udf)
2201    pub language: Option<Ident>,
2202    /// Determinism keyword used for non-sql UDF definitions.
2203    ///
2204    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
2205    pub determinism_specifier: Option<FunctionDeterminismSpecifier>,
2206    /// List of options for creating the function.
2207    ///
2208    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_11)
2209    pub options: Option<Vec<SqlOption>>,
2210    /// Connection resource for a remote function.
2211    ///
2212    /// Example:
2213    /// ```sql
2214    /// CREATE FUNCTION foo()
2215    /// RETURNS FLOAT64
2216    /// REMOTE WITH CONNECTION us.myconnection
2217    /// ```
2218    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
2219    pub remote_connection: Option<ObjectName>,
2220}
2221
2222impl fmt::Display for CreateFunction {
2223    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2224        write!(
2225            f,
2226            "CREATE {or_alter}{or_replace}{temp}FUNCTION {if_not_exists}{name}",
2227            name = self.name,
2228            temp = if self.temporary { "TEMPORARY " } else { "" },
2229            or_alter = if self.or_alter { "OR ALTER " } else { "" },
2230            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
2231            if_not_exists = if self.if_not_exists {
2232                "IF NOT EXISTS "
2233            } else {
2234                ""
2235            },
2236        )?;
2237        if let Some(args) = &self.args {
2238            write!(f, "({})", display_comma_separated(args))?;
2239        }
2240        if let Some(return_type) = &self.return_type {
2241            write!(f, " RETURNS {return_type}")?;
2242        }
2243        if let Some(determinism_specifier) = &self.determinism_specifier {
2244            write!(f, " {determinism_specifier}")?;
2245        }
2246        if let Some(language) = &self.language {
2247            write!(f, " LANGUAGE {language}")?;
2248        }
2249        if let Some(behavior) = &self.behavior {
2250            write!(f, " {behavior}")?;
2251        }
2252        if let Some(called_on_null) = &self.called_on_null {
2253            write!(f, " {called_on_null}")?;
2254        }
2255        if let Some(parallel) = &self.parallel {
2256            write!(f, " {parallel}")?;
2257        }
2258        if let Some(remote_connection) = &self.remote_connection {
2259            write!(f, " REMOTE WITH CONNECTION {remote_connection}")?;
2260        }
2261        if let Some(CreateFunctionBody::AsBeforeOptions(function_body)) = &self.function_body {
2262            write!(f, " AS {function_body}")?;
2263        }
2264        if let Some(CreateFunctionBody::Return(function_body)) = &self.function_body {
2265            write!(f, " RETURN {function_body}")?;
2266        }
2267        if let Some(using) = &self.using {
2268            write!(f, " {using}")?;
2269        }
2270        if let Some(options) = &self.options {
2271            write!(
2272                f,
2273                " OPTIONS({})",
2274                display_comma_separated(options.as_slice())
2275            )?;
2276        }
2277        if let Some(CreateFunctionBody::AsAfterOptions(function_body)) = &self.function_body {
2278            write!(f, " AS {function_body}")?;
2279        }
2280        if let Some(CreateFunctionBody::AsBeginEnd(bes)) = &self.function_body {
2281            write!(f, " AS {bes}")?;
2282        }
2283        Ok(())
2284    }
2285}
2286
2287/// ```sql
2288/// CREATE CONNECTOR [IF NOT EXISTS] connector_name
2289/// [TYPE datasource_type]
2290/// [URL datasource_url]
2291/// [COMMENT connector_comment]
2292/// [WITH DCPROPERTIES(property_name=property_value, ...)]
2293/// ```
2294///
2295/// [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
2296#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2297#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2298#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2299pub struct CreateConnector {
2300    pub name: Ident,
2301    pub if_not_exists: bool,
2302    pub connector_type: Option<String>,
2303    pub url: Option<String>,
2304    pub comment: Option<CommentDef>,
2305    pub with_dcproperties: Option<Vec<SqlOption>>,
2306}
2307
2308impl fmt::Display for CreateConnector {
2309    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2310        write!(
2311            f,
2312            "CREATE CONNECTOR {if_not_exists}{name}",
2313            if_not_exists = if self.if_not_exists {
2314                "IF NOT EXISTS "
2315            } else {
2316                ""
2317            },
2318            name = self.name,
2319        )?;
2320
2321        if let Some(connector_type) = &self.connector_type {
2322            write!(f, " TYPE '{connector_type}'")?;
2323        }
2324
2325        if let Some(url) = &self.url {
2326            write!(f, " URL '{url}'")?;
2327        }
2328
2329        if let Some(comment) = &self.comment {
2330            write!(f, " COMMENT = '{comment}'")?;
2331        }
2332
2333        if let Some(with_dcproperties) = &self.with_dcproperties {
2334            write!(
2335                f,
2336                " WITH DCPROPERTIES({})",
2337                display_comma_separated(with_dcproperties)
2338            )?;
2339        }
2340
2341        Ok(())
2342    }
2343}