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