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