1use 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, string::String, vec::Vec};
30
31#[cfg(feature = "serde")]
32use serde::{Deserialize, Serialize};
33
34#[cfg(feature = "visitor")]
35use sqlparser_derive::{Visit, VisitMut};
36
37#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
40#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
41#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
42pub enum TableConstraint {
43 Unique(UniqueConstraint),
56 PrimaryKey(PrimaryKeyConstraint),
75 ForeignKey(ForeignKeyConstraint),
81 Check(CheckConstraint),
83 Index(IndexConstraint),
90 FulltextOrSpatial(FullTextOrSpatialConstraint),
104 PrimaryKeyUsingIndex(ConstraintUsingIndex),
112 UniqueUsingIndex(ConstraintUsingIndex),
120 Exclude(ExcludeConstraint),
126}
127
128impl From<UniqueConstraint> for TableConstraint {
129 fn from(constraint: UniqueConstraint) -> Self {
130 TableConstraint::Unique(constraint)
131 }
132}
133
134impl From<PrimaryKeyConstraint> for TableConstraint {
135 fn from(constraint: PrimaryKeyConstraint) -> Self {
136 TableConstraint::PrimaryKey(constraint)
137 }
138}
139
140impl From<ForeignKeyConstraint> for TableConstraint {
141 fn from(constraint: ForeignKeyConstraint) -> Self {
142 TableConstraint::ForeignKey(constraint)
143 }
144}
145
146impl From<CheckConstraint> for TableConstraint {
147 fn from(constraint: CheckConstraint) -> Self {
148 TableConstraint::Check(constraint)
149 }
150}
151
152impl From<IndexConstraint> for TableConstraint {
153 fn from(constraint: IndexConstraint) -> Self {
154 TableConstraint::Index(constraint)
155 }
156}
157
158impl From<FullTextOrSpatialConstraint> for TableConstraint {
159 fn from(constraint: FullTextOrSpatialConstraint) -> Self {
160 TableConstraint::FulltextOrSpatial(constraint)
161 }
162}
163
164impl From<ExcludeConstraint> for TableConstraint {
165 fn from(constraint: ExcludeConstraint) -> Self {
166 TableConstraint::Exclude(constraint)
167 }
168}
169
170impl fmt::Display for TableConstraint {
171 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
172 match self {
173 TableConstraint::Unique(constraint) => constraint.fmt(f),
174 TableConstraint::PrimaryKey(constraint) => constraint.fmt(f),
175 TableConstraint::ForeignKey(constraint) => constraint.fmt(f),
176 TableConstraint::Check(constraint) => constraint.fmt(f),
177 TableConstraint::Index(constraint) => constraint.fmt(f),
178 TableConstraint::FulltextOrSpatial(constraint) => constraint.fmt(f),
179 TableConstraint::PrimaryKeyUsingIndex(c) => c.fmt_with_keyword(f, "PRIMARY KEY"),
180 TableConstraint::UniqueUsingIndex(c) => c.fmt_with_keyword(f, "UNIQUE"),
181 TableConstraint::Exclude(constraint) => constraint.fmt(f),
182 }
183 }
184}
185
186#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
187#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
188#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
189pub struct CheckConstraint {
191 pub name: Option<Ident>,
193 pub expr: Box<Expr>,
195 pub no_inherit: bool,
198 pub enforced: Option<bool>,
201}
202
203impl fmt::Display for CheckConstraint {
204 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205 use crate::ast::ddl::display_constraint_name;
206 write!(
207 f,
208 "{}CHECK ({})",
209 display_constraint_name(&self.name),
210 self.expr
211 )?;
212 if self.no_inherit {
213 write!(f, " NO INHERIT")?;
214 }
215 if let Some(b) = self.enforced {
216 write!(f, " {}", if b { "ENFORCED" } else { "NOT ENFORCED" })?;
217 }
218 Ok(())
219 }
220}
221
222impl crate::ast::Spanned for CheckConstraint {
223 fn span(&self) -> Span {
224 self.expr
225 .span()
226 .union_opt(&self.name.as_ref().map(|i| i.span))
227 }
228}
229
230#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
236#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
237#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
238pub struct ForeignKeyConstraint {
239 pub name: Option<Ident>,
241 pub index_name: Option<Ident>,
244 pub columns: Vec<Ident>,
246 pub foreign_table: ObjectName,
248 pub referred_columns: Vec<Ident>,
250 pub on_delete: Option<ReferentialAction>,
252 pub on_update: Option<ReferentialAction>,
254 pub match_kind: Option<ConstraintReferenceMatchKind>,
256 pub characteristics: Option<ConstraintCharacteristics>,
258}
259
260impl fmt::Display for ForeignKeyConstraint {
261 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
262 use crate::ast::ddl::{display_constraint_name, display_option_spaced};
263 write!(
264 f,
265 "{}FOREIGN KEY{} ({}) REFERENCES {}",
266 display_constraint_name(&self.name),
267 display_option_spaced(&self.index_name),
268 display_comma_separated(&self.columns),
269 self.foreign_table,
270 )?;
271 if !self.referred_columns.is_empty() {
272 write!(f, "({})", display_comma_separated(&self.referred_columns))?;
273 }
274 if let Some(match_kind) = &self.match_kind {
275 write!(f, " {match_kind}")?;
276 }
277 if let Some(action) = &self.on_delete {
278 write!(f, " ON DELETE {action}")?;
279 }
280 if let Some(action) = &self.on_update {
281 write!(f, " ON UPDATE {action}")?;
282 }
283 if let Some(characteristics) = &self.characteristics {
284 write!(f, " {characteristics}")?;
285 }
286 Ok(())
287 }
288}
289
290impl crate::ast::Spanned for ForeignKeyConstraint {
291 fn span(&self) -> Span {
292 fn union_spans<I: Iterator<Item = Span>>(iter: I) -> Span {
293 Span::union_iter(iter)
294 }
295
296 union_spans(
297 self.name
298 .iter()
299 .map(|i| i.span)
300 .chain(self.index_name.iter().map(|i| i.span))
301 .chain(self.columns.iter().map(|i| i.span))
302 .chain(core::iter::once(self.foreign_table.span()))
303 .chain(self.referred_columns.iter().map(|i| i.span))
304 .chain(self.on_delete.iter().map(|i| i.span()))
305 .chain(self.on_update.iter().map(|i| i.span()))
306 .chain(self.characteristics.iter().map(|i| i.span())),
307 )
308 }
309}
310
311#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
325#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
326#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
327pub struct FullTextOrSpatialConstraint {
328 pub fulltext: bool,
330 pub index_type_display: KeyOrIndexDisplay,
332 pub opt_index_name: Option<Ident>,
334 pub columns: Vec<IndexColumn>,
336}
337
338impl fmt::Display for FullTextOrSpatialConstraint {
339 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
340 if self.fulltext {
341 write!(f, "FULLTEXT")?;
342 } else {
343 write!(f, "SPATIAL")?;
344 }
345
346 write!(f, "{:>}", self.index_type_display)?;
347
348 if let Some(name) = &self.opt_index_name {
349 write!(f, " {name}")?;
350 }
351
352 write!(f, " ({})", display_comma_separated(&self.columns))?;
353
354 Ok(())
355 }
356}
357
358impl crate::ast::Spanned for FullTextOrSpatialConstraint {
359 fn span(&self) -> Span {
360 fn union_spans<I: Iterator<Item = Span>>(iter: I) -> Span {
361 Span::union_iter(iter)
362 }
363
364 union_spans(
365 self.opt_index_name
366 .iter()
367 .map(|i| i.span)
368 .chain(self.columns.iter().map(|i| i.span())),
369 )
370 }
371}
372
373#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
380#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
381#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
382pub struct IndexConstraint {
383 pub display_as_key: bool,
385 pub name: Option<Ident>,
387 pub index_type: Option<IndexType>,
391 pub columns: Vec<IndexColumn>,
393 pub index_options: Vec<IndexOption>,
396}
397
398impl fmt::Display for IndexConstraint {
399 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
400 write!(f, "{}", if self.display_as_key { "KEY" } else { "INDEX" })?;
401 if let Some(name) = &self.name {
402 write!(f, " {name}")?;
403 }
404 if let Some(index_type) = &self.index_type {
405 write!(f, " USING {index_type}")?;
406 }
407 write!(f, " ({})", display_comma_separated(&self.columns))?;
408 if !self.index_options.is_empty() {
409 write!(f, " {}", display_comma_separated(&self.index_options))?;
410 }
411 Ok(())
412 }
413}
414
415impl crate::ast::Spanned for IndexConstraint {
416 fn span(&self) -> Span {
417 fn union_spans<I: Iterator<Item = Span>>(iter: I) -> Span {
418 Span::union_iter(iter)
419 }
420
421 union_spans(
422 self.name
423 .iter()
424 .map(|i| i.span)
425 .chain(self.columns.iter().map(|i| i.span())),
426 )
427 }
428}
429
430#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
449#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
450#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
451pub struct PrimaryKeyConstraint {
452 pub name: Option<Ident>,
456 pub index_name: Option<Ident>,
458 pub index_type: Option<IndexType>,
462 pub columns: Vec<IndexColumn>,
464 pub include: Vec<Ident>,
466 pub index_options: Vec<IndexOption>,
468 pub characteristics: Option<ConstraintCharacteristics>,
470}
471
472impl fmt::Display for PrimaryKeyConstraint {
473 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
474 use crate::ast::ddl::{display_constraint_name, display_option, display_option_spaced};
475 write!(
476 f,
477 "{}PRIMARY KEY{}{} ({})",
478 display_constraint_name(&self.name),
479 display_option_spaced(&self.index_name),
480 display_option(" USING ", "", &self.index_type),
481 display_comma_separated(&self.columns),
482 )?;
483
484 if !self.include.is_empty() {
485 write!(f, " INCLUDE ({})", display_comma_separated(&self.include))?;
486 }
487
488 if !self.index_options.is_empty() {
489 write!(f, " {}", display_separated(&self.index_options, " "))?;
490 }
491
492 write!(f, "{}", display_option_spaced(&self.characteristics))?;
493 Ok(())
494 }
495}
496
497impl crate::ast::Spanned for PrimaryKeyConstraint {
498 fn span(&self) -> Span {
499 fn union_spans<I: Iterator<Item = Span>>(iter: I) -> Span {
500 Span::union_iter(iter)
501 }
502
503 union_spans(
504 self.name
505 .iter()
506 .map(|i| i.span)
507 .chain(self.index_name.iter().map(|i| i.span))
508 .chain(self.columns.iter().map(|i| i.span()))
509 .chain(self.include.iter().map(|i| i.span))
510 .chain(self.characteristics.iter().map(|i| i.span())),
511 )
512 }
513}
514
515#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
516#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
517#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
518pub struct UniqueConstraint {
520 pub name: Option<Ident>,
524 pub index_name: Option<Ident>,
526 pub index_type_display: KeyOrIndexDisplay,
528 pub index_type: Option<IndexType>,
532 pub columns: Vec<IndexColumn>,
534 pub include: Vec<Ident>,
536 pub index_options: Vec<IndexOption>,
538 pub characteristics: Option<ConstraintCharacteristics>,
540 pub nulls_distinct: NullsDistinctOption,
542}
543
544impl fmt::Display for UniqueConstraint {
545 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
546 use crate::ast::ddl::{display_constraint_name, display_option, display_option_spaced};
547 write!(
548 f,
549 "{}UNIQUE{}{:>}{}{} ({})",
550 display_constraint_name(&self.name),
551 self.nulls_distinct,
552 self.index_type_display,
553 display_option_spaced(&self.index_name),
554 display_option(" USING ", "", &self.index_type),
555 display_comma_separated(&self.columns),
556 )?;
557
558 if !self.include.is_empty() {
559 write!(f, " INCLUDE ({})", display_comma_separated(&self.include))?;
560 }
561
562 if !self.index_options.is_empty() {
563 write!(f, " {}", display_separated(&self.index_options, " "))?;
564 }
565
566 write!(f, "{}", display_option_spaced(&self.characteristics))?;
567 Ok(())
568 }
569}
570
571impl crate::ast::Spanned for UniqueConstraint {
572 fn span(&self) -> Span {
573 fn union_spans<I: Iterator<Item = Span>>(iter: I) -> Span {
574 Span::union_iter(iter)
575 }
576
577 union_spans(
578 self.name
579 .iter()
580 .map(|i| i.span)
581 .chain(self.index_name.iter().map(|i| i.span))
582 .chain(self.columns.iter().map(|i| i.span()))
583 .chain(self.include.iter().map(|i| i.span))
584 .chain(self.characteristics.iter().map(|i| i.span())),
585 )
586 }
587}
588
589#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
596#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
597#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
598pub struct ConstraintUsingIndex {
599 pub name: Option<Ident>,
601 pub index_name: Ident,
603 pub characteristics: Option<ConstraintCharacteristics>,
605}
606
607impl ConstraintUsingIndex {
608 pub fn fmt_with_keyword(&self, f: &mut fmt::Formatter, keyword: &str) -> fmt::Result {
610 use crate::ast::ddl::{display_constraint_name, display_option_spaced};
611 write!(
612 f,
613 "{}{} USING INDEX {}",
614 display_constraint_name(&self.name),
615 keyword,
616 self.index_name,
617 )?;
618 write!(f, "{}", display_option_spaced(&self.characteristics))?;
619 Ok(())
620 }
621}
622
623impl crate::ast::Spanned for ConstraintUsingIndex {
624 fn span(&self) -> Span {
625 let start = self
626 .name
627 .as_ref()
628 .map(|i| i.span)
629 .unwrap_or(self.index_name.span);
630 let end = self
631 .characteristics
632 .as_ref()
633 .map(|c| c.span())
634 .unwrap_or(self.index_name.span);
635 start.union(&end)
636 }
637}
638
639#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
643#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
644#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
645pub enum ExcludeConstraintOperator {
646 Token(String),
648 PGOperator(Vec<String>),
650}
651
652impl fmt::Display for ExcludeConstraintOperator {
653 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
654 match self {
655 ExcludeConstraintOperator::Token(token) => f.write_str(token),
656 ExcludeConstraintOperator::PGOperator(parts) => {
657 write!(f, "OPERATOR({})", display_separated(parts, "."))
658 }
659 }
660 }
661}
662
663#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
667#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
668#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
669pub struct ExcludeConstraintElement {
670 pub column: IndexColumn,
672 pub operator: ExcludeConstraintOperator,
674}
675
676impl fmt::Display for ExcludeConstraintElement {
677 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
678 write!(f, "{} WITH {}", self.column, self.operator)
679 }
680}
681
682#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
686#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
687#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
688pub struct ExcludeConstraint {
689 pub name: Option<Ident>,
691 pub index_method: Option<Ident>,
693 pub elements: Vec<ExcludeConstraintElement>,
695 pub include: Vec<Ident>,
697 pub where_clause: Option<Box<Expr>>,
699 pub characteristics: Option<ConstraintCharacteristics>,
701}
702
703impl fmt::Display for ExcludeConstraint {
704 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
705 use crate::ast::ddl::display_constraint_name;
706 write!(f, "{}EXCLUDE", display_constraint_name(&self.name))?;
707 if let Some(method) = &self.index_method {
708 write!(f, " USING {method}")?;
709 }
710 write!(f, " ({})", display_comma_separated(&self.elements))?;
711 if !self.include.is_empty() {
712 write!(f, " INCLUDE ({})", display_comma_separated(&self.include))?;
713 }
714 if let Some(predicate) = &self.where_clause {
715 write!(f, " WHERE ({predicate})")?;
716 }
717 if let Some(characteristics) = &self.characteristics {
718 write!(f, " {characteristics}")?;
719 }
720 Ok(())
721 }
722}
723
724impl crate::ast::Spanned for ExcludeConstraint {
725 fn span(&self) -> Span {
726 Span::union_iter(
727 self.name
728 .iter()
729 .map(|i| i.span)
730 .chain(self.index_method.iter().map(|i| i.span))
731 .chain(self.elements.iter().map(|e| e.span()))
732 .chain(self.include.iter().map(|i| i.span))
733 .chain(self.where_clause.iter().map(|e| e.span()))
734 .chain(self.characteristics.iter().map(|c| c.span())),
735 )
736 }
737}