Skip to main content

sqlparser/ast/
table_constraints.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//! SQL Abstract Syntax Tree (AST) types for table constraints
19
20use crate::ast::{
21    display_comma_separated, display_separated, ConstraintCharacteristics,
22    ConstraintReferenceMatchKind, Expr, Ident, IndexColumn, IndexOption, IndexType,
23    KeyOrIndexDisplay, NullsDistinctOption, ObjectName, ReferentialAction,
24};
25use crate::tokenizer::Span;
26use core::fmt;
27
28#[cfg(not(feature = "std"))]
29use alloc::{boxed::Box, vec::Vec};
30
31#[cfg(feature = "serde")]
32use serde::{Deserialize, Serialize};
33
34#[cfg(feature = "visitor")]
35use sqlparser_derive::{Visit, VisitMut};
36
37/// A table-level constraint, specified in a `CREATE TABLE` or an
38/// `ALTER TABLE ADD <constraint>` statement.
39#[derive(#[automatically_derived]
impl ::core::fmt::Debug for TableConstraint {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            TableConstraint::Unique(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Unique",
                    &__self_0),
            TableConstraint::PrimaryKey(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "PrimaryKey", &__self_0),
            TableConstraint::ForeignKey(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "ForeignKey", &__self_0),
            TableConstraint::Check(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Check",
                    &__self_0),
            TableConstraint::Index(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Index",
                    &__self_0),
            TableConstraint::FulltextOrSpatial(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "FulltextOrSpatial", &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for TableConstraint {
    #[inline]
    fn clone(&self) -> TableConstraint {
        match self {
            TableConstraint::Unique(__self_0) =>
                TableConstraint::Unique(::core::clone::Clone::clone(__self_0)),
            TableConstraint::PrimaryKey(__self_0) =>
                TableConstraint::PrimaryKey(::core::clone::Clone::clone(__self_0)),
            TableConstraint::ForeignKey(__self_0) =>
                TableConstraint::ForeignKey(::core::clone::Clone::clone(__self_0)),
            TableConstraint::Check(__self_0) =>
                TableConstraint::Check(::core::clone::Clone::clone(__self_0)),
            TableConstraint::Index(__self_0) =>
                TableConstraint::Index(::core::clone::Clone::clone(__self_0)),
            TableConstraint::FulltextOrSpatial(__self_0) =>
                TableConstraint::FulltextOrSpatial(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for TableConstraint {
    #[inline]
    fn eq(&self, other: &TableConstraint) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (TableConstraint::Unique(__self_0),
                    TableConstraint::Unique(__arg1_0)) => __self_0 == __arg1_0,
                (TableConstraint::PrimaryKey(__self_0),
                    TableConstraint::PrimaryKey(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (TableConstraint::ForeignKey(__self_0),
                    TableConstraint::ForeignKey(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (TableConstraint::Check(__self_0),
                    TableConstraint::Check(__arg1_0)) => __self_0 == __arg1_0,
                (TableConstraint::Index(__self_0),
                    TableConstraint::Index(__arg1_0)) => __self_0 == __arg1_0,
                (TableConstraint::FulltextOrSpatial(__self_0),
                    TableConstraint::FulltextOrSpatial(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::PartialOrd for TableConstraint {
    #[inline]
    fn partial_cmp(&self, other: &TableConstraint)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        match (self, other) {
            (TableConstraint::Unique(__self_0),
                TableConstraint::Unique(__arg1_0)) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            (TableConstraint::PrimaryKey(__self_0),
                TableConstraint::PrimaryKey(__arg1_0)) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            (TableConstraint::ForeignKey(__self_0),
                TableConstraint::ForeignKey(__arg1_0)) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            (TableConstraint::Check(__self_0),
                TableConstraint::Check(__arg1_0)) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            (TableConstraint::Index(__self_0),
                TableConstraint::Index(__arg1_0)) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            (TableConstraint::FulltextOrSpatial(__self_0),
                TableConstraint::FulltextOrSpatial(__arg1_0)) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            _ =>
                ::core::cmp::PartialOrd::partial_cmp(&__self_discr,
                    &__arg1_discr),
        }
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Eq for TableConstraint {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<UniqueConstraint>;
        let _: ::core::cmp::AssertParamIsEq<PrimaryKeyConstraint>;
        let _: ::core::cmp::AssertParamIsEq<ForeignKeyConstraint>;
        let _: ::core::cmp::AssertParamIsEq<CheckConstraint>;
        let _: ::core::cmp::AssertParamIsEq<IndexConstraint>;
        let _: ::core::cmp::AssertParamIsEq<FullTextOrSpatialConstraint>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::Ord for TableConstraint {
    #[inline]
    fn cmp(&self, other: &TableConstraint) -> ::core::cmp::Ordering {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) {
            ::core::cmp::Ordering::Equal =>
                match (self, other) {
                    (TableConstraint::Unique(__self_0),
                        TableConstraint::Unique(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    (TableConstraint::PrimaryKey(__self_0),
                        TableConstraint::PrimaryKey(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    (TableConstraint::ForeignKey(__self_0),
                        TableConstraint::ForeignKey(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    (TableConstraint::Check(__self_0),
                        TableConstraint::Check(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    (TableConstraint::Index(__self_0),
                        TableConstraint::Index(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    (TableConstraint::FulltextOrSpatial(__self_0),
                        TableConstraint::FulltextOrSpatial(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    _ => unsafe { ::core::intrinsics::unreachable() }
                },
            cmp => cmp,
        }
    }
}Ord, #[automatically_derived]
impl ::core::hash::Hash for TableConstraint {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state);
        match self {
            TableConstraint::Unique(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            TableConstraint::PrimaryKey(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            TableConstraint::ForeignKey(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            TableConstraint::Check(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            TableConstraint::Index(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            TableConstraint::FulltextOrSpatial(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
        }
    }
}Hash)]
40#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
41#[cfg_attr(feature = "visitor", derive(impl sqlparser::ast::Visit for TableConstraint {
    fn visit<V: sqlparser::ast::Visitor>(&self, visitor: &mut V)
        -> ::std::ops::ControlFlow<V::Break> {
        ::recursive::__impl::stacker::maybe_grow(::recursive::get_minimum_stack_size(),
            ::recursive::get_stack_allocation_size(),
            move || -> ::std::ops::ControlFlow<V::Break>
                {
                    {
                        match self {
                            Self::Unique(_0) => {
                                sqlparser::ast::Visit::visit(_0, visitor)?;
                            }
                            Self::PrimaryKey(_0) => {
                                sqlparser::ast::Visit::visit(_0, visitor)?;
                            }
                            Self::ForeignKey(_0) => {
                                sqlparser::ast::Visit::visit(_0, visitor)?;
                            }
                            Self::Check(_0) => {
                                sqlparser::ast::Visit::visit(_0, visitor)?;
                            }
                            Self::Index(_0) => {
                                sqlparser::ast::Visit::visit(_0, visitor)?;
                            }
                            Self::FulltextOrSpatial(_0) => {
                                sqlparser::ast::Visit::visit(_0, visitor)?;
                            }
                        }
                        ::std::ops::ControlFlow::Continue(())
                    }
                })
    }
}Visit, impl sqlparser::ast::VisitMut for TableConstraint {
    fn visit<V: sqlparser::ast::VisitorMut>(&mut self, visitor: &mut V)
        -> ::std::ops::ControlFlow<V::Break> {
        ::recursive::__impl::stacker::maybe_grow(::recursive::get_minimum_stack_size(),
            ::recursive::get_stack_allocation_size(),
            move || -> ::std::ops::ControlFlow<V::Break>
                {
                    {
                        match self {
                            Self::Unique(_0) => {
                                sqlparser::ast::VisitMut::visit(_0, visitor)?;
                            }
                            Self::PrimaryKey(_0) => {
                                sqlparser::ast::VisitMut::visit(_0, visitor)?;
                            }
                            Self::ForeignKey(_0) => {
                                sqlparser::ast::VisitMut::visit(_0, visitor)?;
                            }
                            Self::Check(_0) => {
                                sqlparser::ast::VisitMut::visit(_0, visitor)?;
                            }
                            Self::Index(_0) => {
                                sqlparser::ast::VisitMut::visit(_0, visitor)?;
                            }
                            Self::FulltextOrSpatial(_0) => {
                                sqlparser::ast::VisitMut::visit(_0, visitor)?;
                            }
                        }
                        ::std::ops::ControlFlow::Continue(())
                    }
                })
    }
}VisitMut))]
42pub enum TableConstraint {
43    /// MySQL [definition][1] for `UNIQUE` constraints statements:\
44    /// * `[CONSTRAINT [<name>]] UNIQUE <index_type_display> [<index_name>] [index_type] (<columns>) <index_options>`
45    ///
46    /// where:
47    /// * [index_type][2] is `USING {BTREE | HASH}`
48    /// * [index_options][3] is `{index_type | COMMENT 'string' | ... %currently unsupported stmts% } ...`
49    /// * [index_type_display][4] is `[INDEX | KEY]`
50    ///
51    /// [1]: https://dev.mysql.com/doc/refman/8.3/en/create-table.html
52    /// [2]: IndexType
53    /// [3]: IndexOption
54    /// [4]: KeyOrIndexDisplay
55    Unique(UniqueConstraint),
56    /// MySQL [definition][1] for `PRIMARY KEY` constraints statements:\
57    /// * `[CONSTRAINT [<name>]] PRIMARY KEY [index_name] [index_type] (<columns>) <index_options>`
58    ///
59    /// Actually the specification have no `[index_name]` but the next query will complete successfully:
60    /// ```sql
61    /// CREATE TABLE unspec_table (
62    ///   xid INT NOT NULL,
63    ///   CONSTRAINT p_name PRIMARY KEY index_name USING BTREE (xid)
64    /// );
65    /// ```
66    ///
67    /// where:
68    /// * [index_type][2] is `USING {BTREE | HASH}`
69    /// * [index_options][3] is `{index_type | COMMENT 'string' | ... %currently unsupported stmts% } ...`
70    ///
71    /// [1]: https://dev.mysql.com/doc/refman/8.3/en/create-table.html
72    /// [2]: IndexType
73    /// [3]: IndexOption
74    PrimaryKey(PrimaryKeyConstraint),
75    /// A referential integrity constraint (`[ CONSTRAINT <name> ] FOREIGN KEY (<columns>)
76    /// REFERENCES <foreign_table> (<referred_columns>)
77    /// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
78    ///   [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
79    /// }`).
80    ForeignKey(ForeignKeyConstraint),
81    /// `[ CONSTRAINT <name> ] CHECK (<expr>) [[NOT] ENFORCED]`
82    Check(CheckConstraint),
83    /// MySQLs [index definition][1] for index creation. Not present on ANSI so, for now, the usage
84    /// is restricted to MySQL, as no other dialects that support this syntax were found.
85    ///
86    /// `{INDEX | KEY} [index_name] [index_type] (key_part,...) [index_option]...`
87    ///
88    /// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
89    Index(IndexConstraint),
90    /// MySQLs [fulltext][1] definition. Since the [`SPATIAL`][2] definition is exactly the same,
91    /// and MySQL displays both the same way, it is part of this definition as well.
92    ///
93    /// Supported syntax:
94    ///
95    /// ```markdown
96    /// {FULLTEXT | SPATIAL} [INDEX | KEY] [index_name] (key_part,...)
97    ///
98    /// key_part: col_name
99    /// ```
100    ///
101    /// [1]: https://dev.mysql.com/doc/refman/8.0/en/fulltext-natural-language.html
102    /// [2]: https://dev.mysql.com/doc/refman/8.0/en/spatial-types.html
103    FulltextOrSpatial(FullTextOrSpatialConstraint),
104}
105
106impl From<UniqueConstraint> for TableConstraint {
107    fn from(constraint: UniqueConstraint) -> Self {
108        TableConstraint::Unique(constraint)
109    }
110}
111
112impl From<PrimaryKeyConstraint> for TableConstraint {
113    fn from(constraint: PrimaryKeyConstraint) -> Self {
114        TableConstraint::PrimaryKey(constraint)
115    }
116}
117
118impl From<ForeignKeyConstraint> for TableConstraint {
119    fn from(constraint: ForeignKeyConstraint) -> Self {
120        TableConstraint::ForeignKey(constraint)
121    }
122}
123
124impl From<CheckConstraint> for TableConstraint {
125    fn from(constraint: CheckConstraint) -> Self {
126        TableConstraint::Check(constraint)
127    }
128}
129
130impl From<IndexConstraint> for TableConstraint {
131    fn from(constraint: IndexConstraint) -> Self {
132        TableConstraint::Index(constraint)
133    }
134}
135
136impl From<FullTextOrSpatialConstraint> for TableConstraint {
137    fn from(constraint: FullTextOrSpatialConstraint) -> Self {
138        TableConstraint::FulltextOrSpatial(constraint)
139    }
140}
141
142impl fmt::Display for TableConstraint {
143    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144        match self {
145            TableConstraint::Unique(constraint) => constraint.fmt(f),
146            TableConstraint::PrimaryKey(constraint) => constraint.fmt(f),
147            TableConstraint::ForeignKey(constraint) => constraint.fmt(f),
148            TableConstraint::Check(constraint) => constraint.fmt(f),
149            TableConstraint::Index(constraint) => constraint.fmt(f),
150            TableConstraint::FulltextOrSpatial(constraint) => constraint.fmt(f),
151        }
152    }
153}
154
155#[derive(#[automatically_derived]
impl ::core::fmt::Debug for CheckConstraint {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f,
            "CheckConstraint", "name", &self.name, "expr", &self.expr,
            "enforced", &&self.enforced)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for CheckConstraint {
    #[inline]
    fn clone(&self) -> CheckConstraint {
        CheckConstraint {
            name: ::core::clone::Clone::clone(&self.name),
            expr: ::core::clone::Clone::clone(&self.expr),
            enforced: ::core::clone::Clone::clone(&self.enforced),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for CheckConstraint {
    #[inline]
    fn eq(&self, other: &CheckConstraint) -> bool {
        self.name == other.name && self.expr == other.expr &&
            self.enforced == other.enforced
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::PartialOrd for CheckConstraint {
    #[inline]
    fn partial_cmp(&self, other: &CheckConstraint)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.name, &other.name) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                match ::core::cmp::PartialOrd::partial_cmp(&self.expr,
                        &other.expr) {
                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                        =>
                        ::core::cmp::PartialOrd::partial_cmp(&self.enforced,
                            &other.enforced),
                    cmp => cmp,
                },
            cmp => cmp,
        }
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Eq for CheckConstraint {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Option<Ident>>;
        let _: ::core::cmp::AssertParamIsEq<Box<Expr>>;
        let _: ::core::cmp::AssertParamIsEq<Option<bool>>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::Ord for CheckConstraint {
    #[inline]
    fn cmp(&self, other: &CheckConstraint) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.name, &other.name) {
            ::core::cmp::Ordering::Equal =>
                match ::core::cmp::Ord::cmp(&self.expr, &other.expr) {
                    ::core::cmp::Ordering::Equal =>
                        ::core::cmp::Ord::cmp(&self.enforced, &other.enforced),
                    cmp => cmp,
                },
            cmp => cmp,
        }
    }
}Ord, #[automatically_derived]
impl ::core::hash::Hash for CheckConstraint {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.name, state);
        ::core::hash::Hash::hash(&self.expr, state);
        ::core::hash::Hash::hash(&self.enforced, state)
    }
}Hash)]
156#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
157#[cfg_attr(feature = "visitor", derive(impl sqlparser::ast::Visit for CheckConstraint {
    fn visit<V: sqlparser::ast::Visitor>(&self, visitor: &mut V)
        -> ::std::ops::ControlFlow<V::Break> {
        ::recursive::__impl::stacker::maybe_grow(::recursive::get_minimum_stack_size(),
            ::recursive::get_stack_allocation_size(),
            move || -> ::std::ops::ControlFlow<V::Break>
                {
                    {
                        sqlparser::ast::Visit::visit(&self.name, visitor)?;
                        sqlparser::ast::Visit::visit(&self.expr, visitor)?;
                        sqlparser::ast::Visit::visit(&self.enforced, visitor)?;
                        ::std::ops::ControlFlow::Continue(())
                    }
                })
    }
}Visit, impl sqlparser::ast::VisitMut for CheckConstraint {
    fn visit<V: sqlparser::ast::VisitorMut>(&mut self, visitor: &mut V)
        -> ::std::ops::ControlFlow<V::Break> {
        ::recursive::__impl::stacker::maybe_grow(::recursive::get_minimum_stack_size(),
            ::recursive::get_stack_allocation_size(),
            move || -> ::std::ops::ControlFlow<V::Break>
                {
                    {
                        sqlparser::ast::VisitMut::visit(&mut self.name, visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.expr, visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.enforced,
                                visitor)?;
                        ::std::ops::ControlFlow::Continue(())
                    }
                })
    }
}VisitMut))]
158/// A `CHECK` constraint (`[ CONSTRAINT <name> ] CHECK (<expr>) [[NOT] ENFORCED]`).
159pub struct CheckConstraint {
160    /// Optional constraint name.
161    pub name: Option<Ident>,
162    /// The boolean expression the CHECK constraint enforces.
163    pub expr: Box<Expr>,
164    /// MySQL-specific `ENFORCED` / `NOT ENFORCED` flag.
165    /// <https://dev.mysql.com/doc/refman/8.4/en/create-table.html>
166    pub enforced: Option<bool>,
167}
168
169impl fmt::Display for CheckConstraint {
170    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
171        use crate::ast::ddl::display_constraint_name;
172        f.write_fmt(format_args!("{0}CHECK ({1})",
        display_constraint_name(&self.name), self.expr))write!(
173            f,
174            "{}CHECK ({})",
175            display_constraint_name(&self.name),
176            self.expr
177        )?;
178        if let Some(b) = self.enforced {
179            f.write_fmt(format_args!(" {0}", if b { "ENFORCED" } else { "NOT ENFORCED" }))write!(f, " {}", if b { "ENFORCED" } else { "NOT ENFORCED" })
180        } else {
181            Ok(())
182        }
183    }
184}
185
186impl crate::ast::Spanned for CheckConstraint {
187    fn span(&self) -> Span {
188        self.expr
189            .span()
190            .union_opt(&self.name.as_ref().map(|i| i.span))
191    }
192}
193
194/// A referential integrity constraint (`[ CONSTRAINT <name> ] FOREIGN KEY (<columns>)
195/// REFERENCES <foreign_table> (<referred_columns>) [ MATCH { FULL | PARTIAL | SIMPLE } ]
196/// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
197///   [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
198/// }`).
199#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ForeignKeyConstraint {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        let names: &'static _ =
            &["name", "index_name", "columns", "foreign_table",
                        "referred_columns", "on_delete", "on_update", "match_kind",
                        "characteristics"];
        let values: &[&dyn ::core::fmt::Debug] =
            &[&self.name, &self.index_name, &self.columns,
                        &self.foreign_table, &self.referred_columns,
                        &self.on_delete, &self.on_update, &self.match_kind,
                        &&self.characteristics];
        ::core::fmt::Formatter::debug_struct_fields_finish(f,
            "ForeignKeyConstraint", names, values)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for ForeignKeyConstraint {
    #[inline]
    fn clone(&self) -> ForeignKeyConstraint {
        ForeignKeyConstraint {
            name: ::core::clone::Clone::clone(&self.name),
            index_name: ::core::clone::Clone::clone(&self.index_name),
            columns: ::core::clone::Clone::clone(&self.columns),
            foreign_table: ::core::clone::Clone::clone(&self.foreign_table),
            referred_columns: ::core::clone::Clone::clone(&self.referred_columns),
            on_delete: ::core::clone::Clone::clone(&self.on_delete),
            on_update: ::core::clone::Clone::clone(&self.on_update),
            match_kind: ::core::clone::Clone::clone(&self.match_kind),
            characteristics: ::core::clone::Clone::clone(&self.characteristics),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for ForeignKeyConstraint {
    #[inline]
    fn eq(&self, other: &ForeignKeyConstraint) -> bool {
        self.name == other.name && self.index_name == other.index_name &&
                                    self.columns == other.columns &&
                                self.foreign_table == other.foreign_table &&
                            self.referred_columns == other.referred_columns &&
                        self.on_delete == other.on_delete &&
                    self.on_update == other.on_update &&
                self.match_kind == other.match_kind &&
            self.characteristics == other.characteristics
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::PartialOrd for ForeignKeyConstraint {
    #[inline]
    fn partial_cmp(&self, other: &ForeignKeyConstraint)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.name, &other.name) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                match ::core::cmp::PartialOrd::partial_cmp(&self.index_name,
                        &other.index_name) {
                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                        =>
                        match ::core::cmp::PartialOrd::partial_cmp(&self.columns,
                                &other.columns) {
                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                =>
                                match ::core::cmp::PartialOrd::partial_cmp(&self.foreign_table,
                                        &other.foreign_table) {
                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                        =>
                                        match ::core::cmp::PartialOrd::partial_cmp(&self.referred_columns,
                                                &other.referred_columns) {
                                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                =>
                                                match ::core::cmp::PartialOrd::partial_cmp(&self.on_delete,
                                                        &other.on_delete) {
                                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                        =>
                                                        match ::core::cmp::PartialOrd::partial_cmp(&self.on_update,
                                                                &other.on_update) {
                                                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                                =>
                                                                match ::core::cmp::PartialOrd::partial_cmp(&self.match_kind,
                                                                        &other.match_kind) {
                                                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                                        =>
                                                                        ::core::cmp::PartialOrd::partial_cmp(&self.characteristics,
                                                                            &other.characteristics),
                                                                    cmp => cmp,
                                                                },
                                                            cmp => cmp,
                                                        },
                                                    cmp => cmp,
                                                },
                                            cmp => cmp,
                                        },
                                    cmp => cmp,
                                },
                            cmp => cmp,
                        },
                    cmp => cmp,
                },
            cmp => cmp,
        }
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Eq for ForeignKeyConstraint {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Option<Ident>>;
        let _: ::core::cmp::AssertParamIsEq<Option<Ident>>;
        let _: ::core::cmp::AssertParamIsEq<Vec<Ident>>;
        let _: ::core::cmp::AssertParamIsEq<ObjectName>;
        let _: ::core::cmp::AssertParamIsEq<Vec<Ident>>;
        let _: ::core::cmp::AssertParamIsEq<Option<ReferentialAction>>;
        let _: ::core::cmp::AssertParamIsEq<Option<ReferentialAction>>;
        let _:
                ::core::cmp::AssertParamIsEq<Option<ConstraintReferenceMatchKind>>;
        let _:
                ::core::cmp::AssertParamIsEq<Option<ConstraintCharacteristics>>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::Ord for ForeignKeyConstraint {
    #[inline]
    fn cmp(&self, other: &ForeignKeyConstraint) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.name, &other.name) {
            ::core::cmp::Ordering::Equal =>
                match ::core::cmp::Ord::cmp(&self.index_name,
                        &other.index_name) {
                    ::core::cmp::Ordering::Equal =>
                        match ::core::cmp::Ord::cmp(&self.columns, &other.columns) {
                            ::core::cmp::Ordering::Equal =>
                                match ::core::cmp::Ord::cmp(&self.foreign_table,
                                        &other.foreign_table) {
                                    ::core::cmp::Ordering::Equal =>
                                        match ::core::cmp::Ord::cmp(&self.referred_columns,
                                                &other.referred_columns) {
                                            ::core::cmp::Ordering::Equal =>
                                                match ::core::cmp::Ord::cmp(&self.on_delete,
                                                        &other.on_delete) {
                                                    ::core::cmp::Ordering::Equal =>
                                                        match ::core::cmp::Ord::cmp(&self.on_update,
                                                                &other.on_update) {
                                                            ::core::cmp::Ordering::Equal =>
                                                                match ::core::cmp::Ord::cmp(&self.match_kind,
                                                                        &other.match_kind) {
                                                                    ::core::cmp::Ordering::Equal =>
                                                                        ::core::cmp::Ord::cmp(&self.characteristics,
                                                                            &other.characteristics),
                                                                    cmp => cmp,
                                                                },
                                                            cmp => cmp,
                                                        },
                                                    cmp => cmp,
                                                },
                                            cmp => cmp,
                                        },
                                    cmp => cmp,
                                },
                            cmp => cmp,
                        },
                    cmp => cmp,
                },
            cmp => cmp,
        }
    }
}Ord, #[automatically_derived]
impl ::core::hash::Hash for ForeignKeyConstraint {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.name, state);
        ::core::hash::Hash::hash(&self.index_name, state);
        ::core::hash::Hash::hash(&self.columns, state);
        ::core::hash::Hash::hash(&self.foreign_table, state);
        ::core::hash::Hash::hash(&self.referred_columns, state);
        ::core::hash::Hash::hash(&self.on_delete, state);
        ::core::hash::Hash::hash(&self.on_update, state);
        ::core::hash::Hash::hash(&self.match_kind, state);
        ::core::hash::Hash::hash(&self.characteristics, state)
    }
}Hash)]
200#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
201#[cfg_attr(feature = "visitor", derive(impl sqlparser::ast::Visit for ForeignKeyConstraint {
    fn visit<V: sqlparser::ast::Visitor>(&self, visitor: &mut V)
        -> ::std::ops::ControlFlow<V::Break> {
        ::recursive::__impl::stacker::maybe_grow(::recursive::get_minimum_stack_size(),
            ::recursive::get_stack_allocation_size(),
            move || -> ::std::ops::ControlFlow<V::Break>
                {
                    {
                        sqlparser::ast::Visit::visit(&self.name, visitor)?;
                        sqlparser::ast::Visit::visit(&self.index_name, visitor)?;
                        sqlparser::ast::Visit::visit(&self.columns, visitor)?;
                        sqlparser::ast::Visit::visit(&self.foreign_table, visitor)?;
                        sqlparser::ast::Visit::visit(&self.referred_columns,
                                visitor)?;
                        sqlparser::ast::Visit::visit(&self.on_delete, visitor)?;
                        sqlparser::ast::Visit::visit(&self.on_update, visitor)?;
                        sqlparser::ast::Visit::visit(&self.match_kind, visitor)?;
                        sqlparser::ast::Visit::visit(&self.characteristics,
                                visitor)?;
                        ::std::ops::ControlFlow::Continue(())
                    }
                })
    }
}Visit, impl sqlparser::ast::VisitMut for ForeignKeyConstraint {
    fn visit<V: sqlparser::ast::VisitorMut>(&mut self, visitor: &mut V)
        -> ::std::ops::ControlFlow<V::Break> {
        ::recursive::__impl::stacker::maybe_grow(::recursive::get_minimum_stack_size(),
            ::recursive::get_stack_allocation_size(),
            move || -> ::std::ops::ControlFlow<V::Break>
                {
                    {
                        sqlparser::ast::VisitMut::visit(&mut self.name, visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.index_name,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.columns,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.foreign_table,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.referred_columns,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.on_delete,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.on_update,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.match_kind,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.characteristics,
                                visitor)?;
                        ::std::ops::ControlFlow::Continue(())
                    }
                })
    }
}VisitMut))]
202pub struct ForeignKeyConstraint {
203    /// Optional constraint name.
204    pub name: Option<Ident>,
205    /// MySQL-specific index name associated with the foreign key.
206    /// <https://dev.mysql.com/doc/refman/8.4/en/create-table-foreign-keys.html>
207    pub index_name: Option<Ident>,
208    /// Columns in the local table that participate in the foreign key.
209    pub columns: Vec<Ident>,
210    /// Referenced foreign table name.
211    pub foreign_table: ObjectName,
212    /// Columns in the referenced table.
213    pub referred_columns: Vec<Ident>,
214    /// Action to perform `ON DELETE`.
215    pub on_delete: Option<ReferentialAction>,
216    /// Action to perform `ON UPDATE`.
217    pub on_update: Option<ReferentialAction>,
218    /// Optional `MATCH` kind (FULL | PARTIAL | SIMPLE).
219    pub match_kind: Option<ConstraintReferenceMatchKind>,
220    /// Optional characteristics (e.g., `DEFERRABLE`).
221    pub characteristics: Option<ConstraintCharacteristics>,
222}
223
224impl fmt::Display for ForeignKeyConstraint {
225    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
226        use crate::ast::ddl::{display_constraint_name, display_option_spaced};
227        f.write_fmt(format_args!("{0}FOREIGN KEY{1} ({2}) REFERENCES {3}",
        display_constraint_name(&self.name),
        display_option_spaced(&self.index_name),
        display_comma_separated(&self.columns), self.foreign_table))write!(
228            f,
229            "{}FOREIGN KEY{} ({}) REFERENCES {}",
230            display_constraint_name(&self.name),
231            display_option_spaced(&self.index_name),
232            display_comma_separated(&self.columns),
233            self.foreign_table,
234        )?;
235        if !self.referred_columns.is_empty() {
236            f.write_fmt(format_args!("({0})",
        display_comma_separated(&self.referred_columns)))write!(f, "({})", display_comma_separated(&self.referred_columns))?;
237        }
238        if let Some(match_kind) = &self.match_kind {
239            f.write_fmt(format_args!(" {0}", match_kind))write!(f, " {match_kind}")?;
240        }
241        if let Some(action) = &self.on_delete {
242            f.write_fmt(format_args!(" ON DELETE {0}", action))write!(f, " ON DELETE {action}")?;
243        }
244        if let Some(action) = &self.on_update {
245            f.write_fmt(format_args!(" ON UPDATE {0}", action))write!(f, " ON UPDATE {action}")?;
246        }
247        if let Some(characteristics) = &self.characteristics {
248            f.write_fmt(format_args!(" {0}", characteristics))write!(f, " {characteristics}")?;
249        }
250        Ok(())
251    }
252}
253
254impl crate::ast::Spanned for ForeignKeyConstraint {
255    fn span(&self) -> Span {
256        fn union_spans<I: Iterator<Item = Span>>(iter: I) -> Span {
257            Span::union_iter(iter)
258        }
259
260        union_spans(
261            self.name
262                .iter()
263                .map(|i| i.span)
264                .chain(self.index_name.iter().map(|i| i.span))
265                .chain(self.columns.iter().map(|i| i.span))
266                .chain(core::iter::once(self.foreign_table.span()))
267                .chain(self.referred_columns.iter().map(|i| i.span))
268                .chain(self.on_delete.iter().map(|i| i.span()))
269                .chain(self.on_update.iter().map(|i| i.span()))
270                .chain(self.characteristics.iter().map(|i| i.span())),
271        )
272    }
273}
274
275/// MySQLs [fulltext][1] definition. Since the [`SPATIAL`][2] definition is exactly the same,
276/// and MySQL displays both the same way, it is part of this definition as well.
277///
278/// Supported syntax:
279///
280/// ```markdown
281/// {FULLTEXT | SPATIAL} [INDEX | KEY] [index_name] (key_part,...)
282///
283/// key_part: col_name
284/// ```
285///
286/// [1]: https://dev.mysql.com/doc/refman/8.0/en/fulltext-natural-language.html
287/// [2]: https://dev.mysql.com/doc/refman/8.0/en/spatial-types.html
288#[derive(#[automatically_derived]
impl ::core::fmt::Debug for FullTextOrSpatialConstraint {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field4_finish(f,
            "FullTextOrSpatialConstraint", "fulltext", &self.fulltext,
            "index_type_display", &self.index_type_display, "opt_index_name",
            &self.opt_index_name, "columns", &&self.columns)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for FullTextOrSpatialConstraint {
    #[inline]
    fn clone(&self) -> FullTextOrSpatialConstraint {
        FullTextOrSpatialConstraint {
            fulltext: ::core::clone::Clone::clone(&self.fulltext),
            index_type_display: ::core::clone::Clone::clone(&self.index_type_display),
            opt_index_name: ::core::clone::Clone::clone(&self.opt_index_name),
            columns: ::core::clone::Clone::clone(&self.columns),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for FullTextOrSpatialConstraint {
    #[inline]
    fn eq(&self, other: &FullTextOrSpatialConstraint) -> bool {
        self.fulltext == other.fulltext &&
                    self.index_type_display == other.index_type_display &&
                self.opt_index_name == other.opt_index_name &&
            self.columns == other.columns
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::PartialOrd for FullTextOrSpatialConstraint {
    #[inline]
    fn partial_cmp(&self, other: &FullTextOrSpatialConstraint)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.fulltext,
                &other.fulltext) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                match ::core::cmp::PartialOrd::partial_cmp(&self.index_type_display,
                        &other.index_type_display) {
                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                        =>
                        match ::core::cmp::PartialOrd::partial_cmp(&self.opt_index_name,
                                &other.opt_index_name) {
                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                =>
                                ::core::cmp::PartialOrd::partial_cmp(&self.columns,
                                    &other.columns),
                            cmp => cmp,
                        },
                    cmp => cmp,
                },
            cmp => cmp,
        }
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Eq for FullTextOrSpatialConstraint {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<bool>;
        let _: ::core::cmp::AssertParamIsEq<KeyOrIndexDisplay>;
        let _: ::core::cmp::AssertParamIsEq<Option<Ident>>;
        let _: ::core::cmp::AssertParamIsEq<Vec<IndexColumn>>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::Ord for FullTextOrSpatialConstraint {
    #[inline]
    fn cmp(&self, other: &FullTextOrSpatialConstraint)
        -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.fulltext, &other.fulltext) {
            ::core::cmp::Ordering::Equal =>
                match ::core::cmp::Ord::cmp(&self.index_type_display,
                        &other.index_type_display) {
                    ::core::cmp::Ordering::Equal =>
                        match ::core::cmp::Ord::cmp(&self.opt_index_name,
                                &other.opt_index_name) {
                            ::core::cmp::Ordering::Equal =>
                                ::core::cmp::Ord::cmp(&self.columns, &other.columns),
                            cmp => cmp,
                        },
                    cmp => cmp,
                },
            cmp => cmp,
        }
    }
}Ord, #[automatically_derived]
impl ::core::hash::Hash for FullTextOrSpatialConstraint {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.fulltext, state);
        ::core::hash::Hash::hash(&self.index_type_display, state);
        ::core::hash::Hash::hash(&self.opt_index_name, state);
        ::core::hash::Hash::hash(&self.columns, state)
    }
}Hash)]
289#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
290#[cfg_attr(feature = "visitor", derive(impl sqlparser::ast::Visit for FullTextOrSpatialConstraint {
    fn visit<V: sqlparser::ast::Visitor>(&self, visitor: &mut V)
        -> ::std::ops::ControlFlow<V::Break> {
        ::recursive::__impl::stacker::maybe_grow(::recursive::get_minimum_stack_size(),
            ::recursive::get_stack_allocation_size(),
            move || -> ::std::ops::ControlFlow<V::Break>
                {
                    {
                        sqlparser::ast::Visit::visit(&self.fulltext, visitor)?;
                        sqlparser::ast::Visit::visit(&self.index_type_display,
                                visitor)?;
                        sqlparser::ast::Visit::visit(&self.opt_index_name,
                                visitor)?;
                        sqlparser::ast::Visit::visit(&self.columns, visitor)?;
                        ::std::ops::ControlFlow::Continue(())
                    }
                })
    }
}Visit, impl sqlparser::ast::VisitMut for FullTextOrSpatialConstraint {
    fn visit<V: sqlparser::ast::VisitorMut>(&mut self, visitor: &mut V)
        -> ::std::ops::ControlFlow<V::Break> {
        ::recursive::__impl::stacker::maybe_grow(::recursive::get_minimum_stack_size(),
            ::recursive::get_stack_allocation_size(),
            move || -> ::std::ops::ControlFlow<V::Break>
                {
                    {
                        sqlparser::ast::VisitMut::visit(&mut self.fulltext,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.index_type_display,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.opt_index_name,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.columns,
                                visitor)?;
                        ::std::ops::ControlFlow::Continue(())
                    }
                })
    }
}VisitMut))]
291pub struct FullTextOrSpatialConstraint {
292    /// Whether this is a `FULLTEXT` (true) or `SPATIAL` (false) definition.
293    pub fulltext: bool,
294    /// Whether the type is followed by the keyword `KEY`, `INDEX`, or no keyword at all.
295    pub index_type_display: KeyOrIndexDisplay,
296    /// Optional index name.
297    pub opt_index_name: Option<Ident>,
298    /// Referred column identifier list.
299    pub columns: Vec<IndexColumn>,
300}
301
302impl fmt::Display for FullTextOrSpatialConstraint {
303    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
304        if self.fulltext {
305            f.write_fmt(format_args!("FULLTEXT"))write!(f, "FULLTEXT")?;
306        } else {
307            f.write_fmt(format_args!("SPATIAL"))write!(f, "SPATIAL")?;
308        }
309
310        f.write_fmt(format_args!("{0:>}", self.index_type_display))write!(f, "{:>}", self.index_type_display)?;
311
312        if let Some(name) = &self.opt_index_name {
313            f.write_fmt(format_args!(" {0}", name))write!(f, " {name}")?;
314        }
315
316        f.write_fmt(format_args!(" ({0})", display_comma_separated(&self.columns)))write!(f, " ({})", display_comma_separated(&self.columns))?;
317
318        Ok(())
319    }
320}
321
322impl crate::ast::Spanned for FullTextOrSpatialConstraint {
323    fn span(&self) -> Span {
324        fn union_spans<I: Iterator<Item = Span>>(iter: I) -> Span {
325            Span::union_iter(iter)
326        }
327
328        union_spans(
329            self.opt_index_name
330                .iter()
331                .map(|i| i.span)
332                .chain(self.columns.iter().map(|i| i.span())),
333        )
334    }
335}
336
337/// MySQLs [index definition][1] for index creation. Not present on ANSI so, for now, the usage
338/// is restricted to MySQL, as no other dialects that support this syntax were found.
339///
340/// `{INDEX | KEY} [index_name] [index_type] (key_part,...) [index_option]...`
341///
342/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
343#[derive(#[automatically_derived]
impl ::core::fmt::Debug for IndexConstraint {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field5_finish(f,
            "IndexConstraint", "display_as_key", &self.display_as_key, "name",
            &self.name, "index_type", &self.index_type, "columns",
            &self.columns, "index_options", &&self.index_options)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for IndexConstraint {
    #[inline]
    fn clone(&self) -> IndexConstraint {
        IndexConstraint {
            display_as_key: ::core::clone::Clone::clone(&self.display_as_key),
            name: ::core::clone::Clone::clone(&self.name),
            index_type: ::core::clone::Clone::clone(&self.index_type),
            columns: ::core::clone::Clone::clone(&self.columns),
            index_options: ::core::clone::Clone::clone(&self.index_options),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for IndexConstraint {
    #[inline]
    fn eq(&self, other: &IndexConstraint) -> bool {
        self.display_as_key == other.display_as_key && self.name == other.name
                    && self.index_type == other.index_type &&
                self.columns == other.columns &&
            self.index_options == other.index_options
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::PartialOrd for IndexConstraint {
    #[inline]
    fn partial_cmp(&self, other: &IndexConstraint)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.display_as_key,
                &other.display_as_key) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                match ::core::cmp::PartialOrd::partial_cmp(&self.name,
                        &other.name) {
                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                        =>
                        match ::core::cmp::PartialOrd::partial_cmp(&self.index_type,
                                &other.index_type) {
                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                =>
                                match ::core::cmp::PartialOrd::partial_cmp(&self.columns,
                                        &other.columns) {
                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                        =>
                                        ::core::cmp::PartialOrd::partial_cmp(&self.index_options,
                                            &other.index_options),
                                    cmp => cmp,
                                },
                            cmp => cmp,
                        },
                    cmp => cmp,
                },
            cmp => cmp,
        }
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Eq for IndexConstraint {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<bool>;
        let _: ::core::cmp::AssertParamIsEq<Option<Ident>>;
        let _: ::core::cmp::AssertParamIsEq<Option<IndexType>>;
        let _: ::core::cmp::AssertParamIsEq<Vec<IndexColumn>>;
        let _: ::core::cmp::AssertParamIsEq<Vec<IndexOption>>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::Ord for IndexConstraint {
    #[inline]
    fn cmp(&self, other: &IndexConstraint) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.display_as_key,
                &other.display_as_key) {
            ::core::cmp::Ordering::Equal =>
                match ::core::cmp::Ord::cmp(&self.name, &other.name) {
                    ::core::cmp::Ordering::Equal =>
                        match ::core::cmp::Ord::cmp(&self.index_type,
                                &other.index_type) {
                            ::core::cmp::Ordering::Equal =>
                                match ::core::cmp::Ord::cmp(&self.columns, &other.columns) {
                                    ::core::cmp::Ordering::Equal =>
                                        ::core::cmp::Ord::cmp(&self.index_options,
                                            &other.index_options),
                                    cmp => cmp,
                                },
                            cmp => cmp,
                        },
                    cmp => cmp,
                },
            cmp => cmp,
        }
    }
}Ord, #[automatically_derived]
impl ::core::hash::Hash for IndexConstraint {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.display_as_key, state);
        ::core::hash::Hash::hash(&self.name, state);
        ::core::hash::Hash::hash(&self.index_type, state);
        ::core::hash::Hash::hash(&self.columns, state);
        ::core::hash::Hash::hash(&self.index_options, state)
    }
}Hash)]
344#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
345#[cfg_attr(feature = "visitor", derive(impl sqlparser::ast::Visit for IndexConstraint {
    fn visit<V: sqlparser::ast::Visitor>(&self, visitor: &mut V)
        -> ::std::ops::ControlFlow<V::Break> {
        ::recursive::__impl::stacker::maybe_grow(::recursive::get_minimum_stack_size(),
            ::recursive::get_stack_allocation_size(),
            move || -> ::std::ops::ControlFlow<V::Break>
                {
                    {
                        sqlparser::ast::Visit::visit(&self.display_as_key,
                                visitor)?;
                        sqlparser::ast::Visit::visit(&self.name, visitor)?;
                        sqlparser::ast::Visit::visit(&self.index_type, visitor)?;
                        sqlparser::ast::Visit::visit(&self.columns, visitor)?;
                        sqlparser::ast::Visit::visit(&self.index_options, visitor)?;
                        ::std::ops::ControlFlow::Continue(())
                    }
                })
    }
}Visit, impl sqlparser::ast::VisitMut for IndexConstraint {
    fn visit<V: sqlparser::ast::VisitorMut>(&mut self, visitor: &mut V)
        -> ::std::ops::ControlFlow<V::Break> {
        ::recursive::__impl::stacker::maybe_grow(::recursive::get_minimum_stack_size(),
            ::recursive::get_stack_allocation_size(),
            move || -> ::std::ops::ControlFlow<V::Break>
                {
                    {
                        sqlparser::ast::VisitMut::visit(&mut self.display_as_key,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.name, visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.index_type,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.columns,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.index_options,
                                visitor)?;
                        ::std::ops::ControlFlow::Continue(())
                    }
                })
    }
}VisitMut))]
346pub struct IndexConstraint {
347    /// Whether this index starts with KEY (true) or INDEX (false), to maintain the same syntax.
348    pub display_as_key: bool,
349    /// Index name.
350    pub name: Option<Ident>,
351    /// Optional [index type][1].
352    ///
353    /// [1]: IndexType
354    pub index_type: Option<IndexType>,
355    /// Referred column identifier list.
356    pub columns: Vec<IndexColumn>,
357    /// Optional index options such as `USING`; see [`IndexOption`].
358    /// Options applied to the index (e.g., `COMMENT`, `WITH` options).
359    pub index_options: Vec<IndexOption>,
360}
361
362impl fmt::Display for IndexConstraint {
363    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
364        f.write_fmt(format_args!("{0}",
        if self.display_as_key { "KEY" } else { "INDEX" }))write!(f, "{}", if self.display_as_key { "KEY" } else { "INDEX" })?;
365        if let Some(name) = &self.name {
366            f.write_fmt(format_args!(" {0}", name))write!(f, " {name}")?;
367        }
368        if let Some(index_type) = &self.index_type {
369            f.write_fmt(format_args!(" USING {0}", index_type))write!(f, " USING {index_type}")?;
370        }
371        f.write_fmt(format_args!(" ({0})", display_comma_separated(&self.columns)))write!(f, " ({})", display_comma_separated(&self.columns))?;
372        if !self.index_options.is_empty() {
373            f.write_fmt(format_args!(" {0}",
        display_comma_separated(&self.index_options)))write!(f, " {}", display_comma_separated(&self.index_options))?;
374        }
375        Ok(())
376    }
377}
378
379impl crate::ast::Spanned for IndexConstraint {
380    fn span(&self) -> Span {
381        fn union_spans<I: Iterator<Item = Span>>(iter: I) -> Span {
382            Span::union_iter(iter)
383        }
384
385        union_spans(
386            self.name
387                .iter()
388                .map(|i| i.span)
389                .chain(self.columns.iter().map(|i| i.span())),
390        )
391    }
392}
393
394/// MySQL [definition][1] for `PRIMARY KEY` constraints statements:
395/// * `[CONSTRAINT [<name>]] PRIMARY KEY [index_name] [index_type] (<columns>) <index_options>`
396///
397/// Actually the specification have no `[index_name]` but the next query will complete successfully:
398/// ```sql
399/// CREATE TABLE unspec_table (
400///   xid INT NOT NULL,
401///   CONSTRAINT p_name PRIMARY KEY index_name USING BTREE (xid)
402/// );
403/// ```
404///
405/// where:
406/// * [index_type][2] is `USING {BTREE | HASH}`
407/// * [index_options][3] is `{index_type | COMMENT 'string' | ... %currently unsupported stmts% } ...`
408///
409/// [1]: https://dev.mysql.com/doc/refman/8.3/en/create-table.html
410/// [2]: IndexType
411/// [3]: IndexOption
412#[derive(#[automatically_derived]
impl ::core::fmt::Debug for PrimaryKeyConstraint {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        let names: &'static _ =
            &["name", "index_name", "index_type", "columns", "index_options",
                        "characteristics"];
        let values: &[&dyn ::core::fmt::Debug] =
            &[&self.name, &self.index_name, &self.index_type, &self.columns,
                        &self.index_options, &&self.characteristics];
        ::core::fmt::Formatter::debug_struct_fields_finish(f,
            "PrimaryKeyConstraint", names, values)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for PrimaryKeyConstraint {
    #[inline]
    fn clone(&self) -> PrimaryKeyConstraint {
        PrimaryKeyConstraint {
            name: ::core::clone::Clone::clone(&self.name),
            index_name: ::core::clone::Clone::clone(&self.index_name),
            index_type: ::core::clone::Clone::clone(&self.index_type),
            columns: ::core::clone::Clone::clone(&self.columns),
            index_options: ::core::clone::Clone::clone(&self.index_options),
            characteristics: ::core::clone::Clone::clone(&self.characteristics),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for PrimaryKeyConstraint {
    #[inline]
    fn eq(&self, other: &PrimaryKeyConstraint) -> bool {
        self.name == other.name && self.index_name == other.index_name &&
                        self.index_type == other.index_type &&
                    self.columns == other.columns &&
                self.index_options == other.index_options &&
            self.characteristics == other.characteristics
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::PartialOrd for PrimaryKeyConstraint {
    #[inline]
    fn partial_cmp(&self, other: &PrimaryKeyConstraint)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.name, &other.name) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                match ::core::cmp::PartialOrd::partial_cmp(&self.index_name,
                        &other.index_name) {
                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                        =>
                        match ::core::cmp::PartialOrd::partial_cmp(&self.index_type,
                                &other.index_type) {
                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                =>
                                match ::core::cmp::PartialOrd::partial_cmp(&self.columns,
                                        &other.columns) {
                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                        =>
                                        match ::core::cmp::PartialOrd::partial_cmp(&self.index_options,
                                                &other.index_options) {
                                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                =>
                                                ::core::cmp::PartialOrd::partial_cmp(&self.characteristics,
                                                    &other.characteristics),
                                            cmp => cmp,
                                        },
                                    cmp => cmp,
                                },
                            cmp => cmp,
                        },
                    cmp => cmp,
                },
            cmp => cmp,
        }
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Eq for PrimaryKeyConstraint {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Option<Ident>>;
        let _: ::core::cmp::AssertParamIsEq<Option<Ident>>;
        let _: ::core::cmp::AssertParamIsEq<Option<IndexType>>;
        let _: ::core::cmp::AssertParamIsEq<Vec<IndexColumn>>;
        let _: ::core::cmp::AssertParamIsEq<Vec<IndexOption>>;
        let _:
                ::core::cmp::AssertParamIsEq<Option<ConstraintCharacteristics>>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::Ord for PrimaryKeyConstraint {
    #[inline]
    fn cmp(&self, other: &PrimaryKeyConstraint) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.name, &other.name) {
            ::core::cmp::Ordering::Equal =>
                match ::core::cmp::Ord::cmp(&self.index_name,
                        &other.index_name) {
                    ::core::cmp::Ordering::Equal =>
                        match ::core::cmp::Ord::cmp(&self.index_type,
                                &other.index_type) {
                            ::core::cmp::Ordering::Equal =>
                                match ::core::cmp::Ord::cmp(&self.columns, &other.columns) {
                                    ::core::cmp::Ordering::Equal =>
                                        match ::core::cmp::Ord::cmp(&self.index_options,
                                                &other.index_options) {
                                            ::core::cmp::Ordering::Equal =>
                                                ::core::cmp::Ord::cmp(&self.characteristics,
                                                    &other.characteristics),
                                            cmp => cmp,
                                        },
                                    cmp => cmp,
                                },
                            cmp => cmp,
                        },
                    cmp => cmp,
                },
            cmp => cmp,
        }
    }
}Ord, #[automatically_derived]
impl ::core::hash::Hash for PrimaryKeyConstraint {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.name, state);
        ::core::hash::Hash::hash(&self.index_name, state);
        ::core::hash::Hash::hash(&self.index_type, state);
        ::core::hash::Hash::hash(&self.columns, state);
        ::core::hash::Hash::hash(&self.index_options, state);
        ::core::hash::Hash::hash(&self.characteristics, state)
    }
}Hash)]
413#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
414#[cfg_attr(feature = "visitor", derive(impl sqlparser::ast::Visit for PrimaryKeyConstraint {
    fn visit<V: sqlparser::ast::Visitor>(&self, visitor: &mut V)
        -> ::std::ops::ControlFlow<V::Break> {
        ::recursive::__impl::stacker::maybe_grow(::recursive::get_minimum_stack_size(),
            ::recursive::get_stack_allocation_size(),
            move || -> ::std::ops::ControlFlow<V::Break>
                {
                    {
                        sqlparser::ast::Visit::visit(&self.name, visitor)?;
                        sqlparser::ast::Visit::visit(&self.index_name, visitor)?;
                        sqlparser::ast::Visit::visit(&self.index_type, visitor)?;
                        sqlparser::ast::Visit::visit(&self.columns, visitor)?;
                        sqlparser::ast::Visit::visit(&self.index_options, visitor)?;
                        sqlparser::ast::Visit::visit(&self.characteristics,
                                visitor)?;
                        ::std::ops::ControlFlow::Continue(())
                    }
                })
    }
}Visit, impl sqlparser::ast::VisitMut for PrimaryKeyConstraint {
    fn visit<V: sqlparser::ast::VisitorMut>(&mut self, visitor: &mut V)
        -> ::std::ops::ControlFlow<V::Break> {
        ::recursive::__impl::stacker::maybe_grow(::recursive::get_minimum_stack_size(),
            ::recursive::get_stack_allocation_size(),
            move || -> ::std::ops::ControlFlow<V::Break>
                {
                    {
                        sqlparser::ast::VisitMut::visit(&mut self.name, visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.index_name,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.index_type,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.columns,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.index_options,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.characteristics,
                                visitor)?;
                        ::std::ops::ControlFlow::Continue(())
                    }
                })
    }
}VisitMut))]
415pub struct PrimaryKeyConstraint {
416    /// Constraint name.
417    ///
418    /// Can be not the same as `index_name`
419    pub name: Option<Ident>,
420    /// Index name
421    pub index_name: Option<Ident>,
422    /// Optional `USING` of [index type][1] statement before columns.
423    ///
424    /// [1]: IndexType
425    pub index_type: Option<IndexType>,
426    /// Identifiers of the columns that form the primary key.
427    pub columns: Vec<IndexColumn>,
428    /// Optional index options such as `USING`.
429    pub index_options: Vec<IndexOption>,
430    /// Optional characteristics like `DEFERRABLE`.
431    pub characteristics: Option<ConstraintCharacteristics>,
432}
433
434impl fmt::Display for PrimaryKeyConstraint {
435    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
436        use crate::ast::ddl::{display_constraint_name, display_option, display_option_spaced};
437        f.write_fmt(format_args!("{0}PRIMARY KEY{1}{2} ({3})",
        display_constraint_name(&self.name),
        display_option_spaced(&self.index_name),
        display_option(" USING ", "", &self.index_type),
        display_comma_separated(&self.columns)))write!(
438            f,
439            "{}PRIMARY KEY{}{} ({})",
440            display_constraint_name(&self.name),
441            display_option_spaced(&self.index_name),
442            display_option(" USING ", "", &self.index_type),
443            display_comma_separated(&self.columns),
444        )?;
445
446        if !self.index_options.is_empty() {
447            f.write_fmt(format_args!(" {0}", display_separated(&self.index_options, " ")))write!(f, " {}", display_separated(&self.index_options, " "))?;
448        }
449
450        f.write_fmt(format_args!("{0}", display_option_spaced(&self.characteristics)))write!(f, "{}", display_option_spaced(&self.characteristics))?;
451        Ok(())
452    }
453}
454
455impl crate::ast::Spanned for PrimaryKeyConstraint {
456    fn span(&self) -> Span {
457        fn union_spans<I: Iterator<Item = Span>>(iter: I) -> Span {
458            Span::union_iter(iter)
459        }
460
461        union_spans(
462            self.name
463                .iter()
464                .map(|i| i.span)
465                .chain(self.index_name.iter().map(|i| i.span))
466                .chain(self.columns.iter().map(|i| i.span()))
467                .chain(self.characteristics.iter().map(|i| i.span())),
468        )
469    }
470}
471
472#[derive(#[automatically_derived]
impl ::core::fmt::Debug for UniqueConstraint {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        let names: &'static _ =
            &["name", "index_name", "index_type_display", "index_type",
                        "columns", "index_options", "characteristics",
                        "nulls_distinct"];
        let values: &[&dyn ::core::fmt::Debug] =
            &[&self.name, &self.index_name, &self.index_type_display,
                        &self.index_type, &self.columns, &self.index_options,
                        &self.characteristics, &&self.nulls_distinct];
        ::core::fmt::Formatter::debug_struct_fields_finish(f,
            "UniqueConstraint", names, values)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for UniqueConstraint {
    #[inline]
    fn clone(&self) -> UniqueConstraint {
        UniqueConstraint {
            name: ::core::clone::Clone::clone(&self.name),
            index_name: ::core::clone::Clone::clone(&self.index_name),
            index_type_display: ::core::clone::Clone::clone(&self.index_type_display),
            index_type: ::core::clone::Clone::clone(&self.index_type),
            columns: ::core::clone::Clone::clone(&self.columns),
            index_options: ::core::clone::Clone::clone(&self.index_options),
            characteristics: ::core::clone::Clone::clone(&self.characteristics),
            nulls_distinct: ::core::clone::Clone::clone(&self.nulls_distinct),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for UniqueConstraint {
    #[inline]
    fn eq(&self, other: &UniqueConstraint) -> bool {
        self.name == other.name && self.index_name == other.index_name &&
                                self.index_type_display == other.index_type_display &&
                            self.index_type == other.index_type &&
                        self.columns == other.columns &&
                    self.index_options == other.index_options &&
                self.characteristics == other.characteristics &&
            self.nulls_distinct == other.nulls_distinct
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::PartialOrd for UniqueConstraint {
    #[inline]
    fn partial_cmp(&self, other: &UniqueConstraint)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.name, &other.name) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                match ::core::cmp::PartialOrd::partial_cmp(&self.index_name,
                        &other.index_name) {
                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                        =>
                        match ::core::cmp::PartialOrd::partial_cmp(&self.index_type_display,
                                &other.index_type_display) {
                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                =>
                                match ::core::cmp::PartialOrd::partial_cmp(&self.index_type,
                                        &other.index_type) {
                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                        =>
                                        match ::core::cmp::PartialOrd::partial_cmp(&self.columns,
                                                &other.columns) {
                                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                =>
                                                match ::core::cmp::PartialOrd::partial_cmp(&self.index_options,
                                                        &other.index_options) {
                                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                        =>
                                                        match ::core::cmp::PartialOrd::partial_cmp(&self.characteristics,
                                                                &other.characteristics) {
                                                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                                =>
                                                                ::core::cmp::PartialOrd::partial_cmp(&self.nulls_distinct,
                                                                    &other.nulls_distinct),
                                                            cmp => cmp,
                                                        },
                                                    cmp => cmp,
                                                },
                                            cmp => cmp,
                                        },
                                    cmp => cmp,
                                },
                            cmp => cmp,
                        },
                    cmp => cmp,
                },
            cmp => cmp,
        }
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Eq for UniqueConstraint {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Option<Ident>>;
        let _: ::core::cmp::AssertParamIsEq<Option<Ident>>;
        let _: ::core::cmp::AssertParamIsEq<KeyOrIndexDisplay>;
        let _: ::core::cmp::AssertParamIsEq<Option<IndexType>>;
        let _: ::core::cmp::AssertParamIsEq<Vec<IndexColumn>>;
        let _: ::core::cmp::AssertParamIsEq<Vec<IndexOption>>;
        let _:
                ::core::cmp::AssertParamIsEq<Option<ConstraintCharacteristics>>;
        let _: ::core::cmp::AssertParamIsEq<NullsDistinctOption>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::Ord for UniqueConstraint {
    #[inline]
    fn cmp(&self, other: &UniqueConstraint) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.name, &other.name) {
            ::core::cmp::Ordering::Equal =>
                match ::core::cmp::Ord::cmp(&self.index_name,
                        &other.index_name) {
                    ::core::cmp::Ordering::Equal =>
                        match ::core::cmp::Ord::cmp(&self.index_type_display,
                                &other.index_type_display) {
                            ::core::cmp::Ordering::Equal =>
                                match ::core::cmp::Ord::cmp(&self.index_type,
                                        &other.index_type) {
                                    ::core::cmp::Ordering::Equal =>
                                        match ::core::cmp::Ord::cmp(&self.columns, &other.columns) {
                                            ::core::cmp::Ordering::Equal =>
                                                match ::core::cmp::Ord::cmp(&self.index_options,
                                                        &other.index_options) {
                                                    ::core::cmp::Ordering::Equal =>
                                                        match ::core::cmp::Ord::cmp(&self.characteristics,
                                                                &other.characteristics) {
                                                            ::core::cmp::Ordering::Equal =>
                                                                ::core::cmp::Ord::cmp(&self.nulls_distinct,
                                                                    &other.nulls_distinct),
                                                            cmp => cmp,
                                                        },
                                                    cmp => cmp,
                                                },
                                            cmp => cmp,
                                        },
                                    cmp => cmp,
                                },
                            cmp => cmp,
                        },
                    cmp => cmp,
                },
            cmp => cmp,
        }
    }
}Ord, #[automatically_derived]
impl ::core::hash::Hash for UniqueConstraint {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.name, state);
        ::core::hash::Hash::hash(&self.index_name, state);
        ::core::hash::Hash::hash(&self.index_type_display, state);
        ::core::hash::Hash::hash(&self.index_type, state);
        ::core::hash::Hash::hash(&self.columns, state);
        ::core::hash::Hash::hash(&self.index_options, state);
        ::core::hash::Hash::hash(&self.characteristics, state);
        ::core::hash::Hash::hash(&self.nulls_distinct, state)
    }
}Hash)]
473#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
474#[cfg_attr(feature = "visitor", derive(impl sqlparser::ast::Visit for UniqueConstraint {
    fn visit<V: sqlparser::ast::Visitor>(&self, visitor: &mut V)
        -> ::std::ops::ControlFlow<V::Break> {
        ::recursive::__impl::stacker::maybe_grow(::recursive::get_minimum_stack_size(),
            ::recursive::get_stack_allocation_size(),
            move || -> ::std::ops::ControlFlow<V::Break>
                {
                    {
                        sqlparser::ast::Visit::visit(&self.name, visitor)?;
                        sqlparser::ast::Visit::visit(&self.index_name, visitor)?;
                        sqlparser::ast::Visit::visit(&self.index_type_display,
                                visitor)?;
                        sqlparser::ast::Visit::visit(&self.index_type, visitor)?;
                        sqlparser::ast::Visit::visit(&self.columns, visitor)?;
                        sqlparser::ast::Visit::visit(&self.index_options, visitor)?;
                        sqlparser::ast::Visit::visit(&self.characteristics,
                                visitor)?;
                        sqlparser::ast::Visit::visit(&self.nulls_distinct,
                                visitor)?;
                        ::std::ops::ControlFlow::Continue(())
                    }
                })
    }
}Visit, impl sqlparser::ast::VisitMut for UniqueConstraint {
    fn visit<V: sqlparser::ast::VisitorMut>(&mut self, visitor: &mut V)
        -> ::std::ops::ControlFlow<V::Break> {
        ::recursive::__impl::stacker::maybe_grow(::recursive::get_minimum_stack_size(),
            ::recursive::get_stack_allocation_size(),
            move || -> ::std::ops::ControlFlow<V::Break>
                {
                    {
                        sqlparser::ast::VisitMut::visit(&mut self.name, visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.index_name,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.index_type_display,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.index_type,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.columns,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.index_options,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.characteristics,
                                visitor)?;
                        sqlparser::ast::VisitMut::visit(&mut self.nulls_distinct,
                                visitor)?;
                        ::std::ops::ControlFlow::Continue(())
                    }
                })
    }
}VisitMut))]
475/// Unique constraint definition.
476pub struct UniqueConstraint {
477    /// Constraint name.
478    ///
479    /// Can be not the same as `index_name`
480    pub name: Option<Ident>,
481    /// Index name
482    pub index_name: Option<Ident>,
483    /// Whether the type is followed by the keyword `KEY`, `INDEX`, or no keyword at all.
484    pub index_type_display: KeyOrIndexDisplay,
485    /// Optional `USING` of [index type][1] statement before columns.
486    ///
487    /// [1]: IndexType
488    pub index_type: Option<IndexType>,
489    /// Identifiers of the columns that are unique.
490    pub columns: Vec<IndexColumn>,
491    /// Optional index options such as `USING`.
492    pub index_options: Vec<IndexOption>,
493    /// Optional characteristics like `DEFERRABLE`.
494    pub characteristics: Option<ConstraintCharacteristics>,
495    /// Optional Postgres nulls handling: `[ NULLS [ NOT ] DISTINCT ]`
496    pub nulls_distinct: NullsDistinctOption,
497}
498
499impl fmt::Display for UniqueConstraint {
500    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
501        use crate::ast::ddl::{display_constraint_name, display_option, display_option_spaced};
502        f.write_fmt(format_args!("{0}UNIQUE{1}{2:>}{3}{4} ({5})",
        display_constraint_name(&self.name), self.nulls_distinct,
        self.index_type_display, display_option_spaced(&self.index_name),
        display_option(" USING ", "", &self.index_type),
        display_comma_separated(&self.columns)))write!(
503            f,
504            "{}UNIQUE{}{:>}{}{} ({})",
505            display_constraint_name(&self.name),
506            self.nulls_distinct,
507            self.index_type_display,
508            display_option_spaced(&self.index_name),
509            display_option(" USING ", "", &self.index_type),
510            display_comma_separated(&self.columns),
511        )?;
512
513        if !self.index_options.is_empty() {
514            f.write_fmt(format_args!(" {0}", display_separated(&self.index_options, " ")))write!(f, " {}", display_separated(&self.index_options, " "))?;
515        }
516
517        f.write_fmt(format_args!("{0}", display_option_spaced(&self.characteristics)))write!(f, "{}", display_option_spaced(&self.characteristics))?;
518        Ok(())
519    }
520}
521
522impl crate::ast::Spanned for UniqueConstraint {
523    fn span(&self) -> Span {
524        fn union_spans<I: Iterator<Item = Span>>(iter: I) -> Span {
525            Span::union_iter(iter)
526        }
527
528        union_spans(
529            self.name
530                .iter()
531                .map(|i| i.span)
532                .chain(self.index_name.iter().map(|i| i.span))
533                .chain(self.columns.iter().map(|i| i.span()))
534                .chain(self.characteristics.iter().map(|i| i.span())),
535        )
536    }
537}