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