@@ -384,6 +384,7 @@ pub enum TableConstraint {
384
384
columns : Vec < Ident > ,
385
385
/// Whether this is a `PRIMARY KEY` or just a `UNIQUE` constraint
386
386
is_primary : bool ,
387
+ characteristics : Option < ConstraintCharacteristics > ,
387
388
} ,
388
389
/// A referential integrity constraint (`[ CONSTRAINT <name> ] FOREIGN KEY (<columns>)
389
390
/// REFERENCES <foreign_table> (<referred_columns>)
@@ -397,6 +398,7 @@ pub enum TableConstraint {
397
398
referred_columns : Vec < Ident > ,
398
399
on_delete : Option < ReferentialAction > ,
399
400
on_update : Option < ReferentialAction > ,
401
+ characteristics : Option < ConstraintCharacteristics > ,
400
402
} ,
401
403
/// `[ CONSTRAINT <name> ] CHECK (<expr>)`
402
404
Check {
@@ -453,20 +455,30 @@ impl fmt::Display for TableConstraint {
453
455
name,
454
456
columns,
455
457
is_primary,
456
- } => write ! (
457
- f,
458
- "{}{} ({})" ,
459
- display_constraint_name( name) ,
460
- if * is_primary { "PRIMARY KEY" } else { "UNIQUE" } ,
461
- display_comma_separated( columns)
462
- ) ,
458
+ characteristics,
459
+ } => {
460
+ write ! (
461
+ f,
462
+ "{}{} ({})" ,
463
+ display_constraint_name( name) ,
464
+ if * is_primary { "PRIMARY KEY" } else { "UNIQUE" } ,
465
+ display_comma_separated( columns)
466
+ ) ?;
467
+
468
+ if let Some ( characteristics) = characteristics {
469
+ write ! ( f, " {}" , characteristics) ?;
470
+ }
471
+
472
+ Ok ( ( ) )
473
+ }
463
474
TableConstraint :: ForeignKey {
464
475
name,
465
476
columns,
466
477
foreign_table,
467
478
referred_columns,
468
479
on_delete,
469
480
on_update,
481
+ characteristics,
470
482
} => {
471
483
write ! (
472
484
f,
@@ -482,6 +494,9 @@ impl fmt::Display for TableConstraint {
482
494
if let Some ( action) = on_update {
483
495
write ! ( f, " ON UPDATE {action}" ) ?;
484
496
}
497
+ if let Some ( characteristics) = characteristics {
498
+ write ! ( f, " {}" , characteristics) ?;
499
+ }
485
500
Ok ( ( ) )
486
501
}
487
502
TableConstraint :: Check { name, expr } => {
@@ -676,20 +691,24 @@ pub enum ColumnOption {
676
691
NotNull ,
677
692
/// `DEFAULT <restricted-expr>`
678
693
Default ( Expr ) ,
679
- /// `{ PRIMARY KEY | UNIQUE }`
694
+ /// `{ PRIMARY KEY | UNIQUE } [<constraint_characteristics>] `
680
695
Unique {
681
696
is_primary : bool ,
697
+ characteristics : Option < ConstraintCharacteristics > ,
682
698
} ,
683
699
/// A referential integrity constraint (`[FOREIGN KEY REFERENCES
684
700
/// <foreign_table> (<referred_columns>)
685
701
/// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
686
702
/// [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
687
- /// }`).
703
+ /// }
704
+ /// [<constraint_characteristics>]
705
+ /// `).
688
706
ForeignKey {
689
707
foreign_table : ObjectName ,
690
708
referred_columns : Vec < Ident > ,
691
709
on_delete : Option < ReferentialAction > ,
692
710
on_update : Option < ReferentialAction > ,
711
+ characteristics : Option < ConstraintCharacteristics > ,
693
712
} ,
694
713
/// `CHECK (<expr>)`
695
714
Check ( Expr ) ,
@@ -719,14 +738,22 @@ impl fmt::Display for ColumnOption {
719
738
Null => write ! ( f, "NULL" ) ,
720
739
NotNull => write ! ( f, "NOT NULL" ) ,
721
740
Default ( expr) => write ! ( f, "DEFAULT {expr}" ) ,
722
- Unique { is_primary } => {
723
- write ! ( f, "{}" , if * is_primary { "PRIMARY KEY" } else { "UNIQUE" } )
741
+ Unique {
742
+ is_primary,
743
+ characteristics,
744
+ } => {
745
+ write ! ( f, "{}" , if * is_primary { "PRIMARY KEY" } else { "UNIQUE" } ) ?;
746
+ if let Some ( characteristics) = characteristics {
747
+ write ! ( f, " {}" , characteristics) ?;
748
+ }
749
+ Ok ( ( ) )
724
750
}
725
751
ForeignKey {
726
752
foreign_table,
727
753
referred_columns,
728
754
on_delete,
729
755
on_update,
756
+ characteristics,
730
757
} => {
731
758
write ! ( f, "REFERENCES {foreign_table}" ) ?;
732
759
if !referred_columns. is_empty ( ) {
@@ -738,6 +765,9 @@ impl fmt::Display for ColumnOption {
738
765
if let Some ( action) = on_update {
739
766
write ! ( f, " ON UPDATE {action}" ) ?;
740
767
}
768
+ if let Some ( characteristics) = characteristics {
769
+ write ! ( f, " {}" , characteristics) ?;
770
+ }
741
771
Ok ( ( ) )
742
772
}
743
773
Check ( expr) => write ! ( f, "CHECK ({expr})" ) ,
@@ -826,6 +856,84 @@ fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
826
856
ConstraintName ( name)
827
857
}
828
858
859
+ /// `<constraint_characteristics> = [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ]`
860
+ ///
861
+ /// Used in UNIQUE and foreign key constraints. The individual settings may occur in any order.
862
+ #[ derive( Debug , Copy , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
863
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
864
+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
865
+ pub struct ConstraintCharacteristics {
866
+ /// `[ DEFERRABLE | NOT DEFERRABLE ]`
867
+ pub deferrable : Option < bool > ,
868
+ /// `[ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]`
869
+ pub initially : Option < DeferrableInitial > ,
870
+ /// `[ ENFORCED | NOT ENFORCED ]`
871
+ pub enforced : Option < bool > ,
872
+ }
873
+
874
+ #[ derive( Debug , Copy , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
875
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
876
+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
877
+ pub enum DeferrableInitial {
878
+ /// `INITIALLY IMMEDIATE`
879
+ Immediate ,
880
+ /// `INITIALLY DEFERRED`
881
+ Deferred ,
882
+ }
883
+
884
+ impl ConstraintCharacteristics {
885
+ fn deferrable_text ( & self ) -> Option < & ' static str > {
886
+ self . deferrable . map ( |deferrable| {
887
+ if deferrable {
888
+ "DEFERRABLE"
889
+ } else {
890
+ "NOT DEFERRABLE"
891
+ }
892
+ } )
893
+ }
894
+
895
+ fn initially_immediate_text ( & self ) -> Option < & ' static str > {
896
+ self . initially
897
+ . map ( |initially_immediate| match initially_immediate {
898
+ DeferrableInitial :: Immediate => "INITIALLY IMMEDIATE" ,
899
+ DeferrableInitial :: Deferred => "INITIALLY DEFERRED" ,
900
+ } )
901
+ }
902
+
903
+ fn enforced_text ( & self ) -> Option < & ' static str > {
904
+ self . enforced . map (
905
+ |enforced| {
906
+ if enforced {
907
+ "ENFORCED"
908
+ } else {
909
+ "NOT ENFORCED"
910
+ }
911
+ } ,
912
+ )
913
+ }
914
+ }
915
+
916
+ impl fmt:: Display for ConstraintCharacteristics {
917
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
918
+ let deferrable = self . deferrable_text ( ) ;
919
+ let initially_immediate = self . initially_immediate_text ( ) ;
920
+ let enforced = self . enforced_text ( ) ;
921
+
922
+ match ( deferrable, initially_immediate, enforced) {
923
+ ( None , None , None ) => Ok ( ( ) ) ,
924
+ ( None , None , Some ( enforced) ) => write ! ( f, "{enforced}" ) ,
925
+ ( None , Some ( initial) , None ) => write ! ( f, "{initial}" ) ,
926
+ ( None , Some ( initial) , Some ( enforced) ) => write ! ( f, "{initial} {enforced}" ) ,
927
+ ( Some ( deferrable) , None , None ) => write ! ( f, "{deferrable}" ) ,
928
+ ( Some ( deferrable) , None , Some ( enforced) ) => write ! ( f, "{deferrable} {enforced}" ) ,
929
+ ( Some ( deferrable) , Some ( initial) , None ) => write ! ( f, "{deferrable} {initial}" ) ,
930
+ ( Some ( deferrable) , Some ( initial) , Some ( enforced) ) => {
931
+ write ! ( f, "{deferrable} {initial} {enforced}" )
932
+ }
933
+ }
934
+ }
935
+ }
936
+
829
937
/// `<referential_action> =
830
938
/// { RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT }`
831
939
///
0 commit comments