@@ -385,6 +385,7 @@ pub enum TableConstraint {
385
385
columns : Vec < Ident > ,
386
386
/// Whether this is a `PRIMARY KEY` or just a `UNIQUE` constraint
387
387
is_primary : bool ,
388
+ characteristics : Option < ConstraintCharacteristics > ,
388
389
} ,
389
390
/// A referential integrity constraint (`[ CONSTRAINT <name> ] FOREIGN KEY (<columns>)
390
391
/// REFERENCES <foreign_table> (<referred_columns>)
@@ -398,6 +399,7 @@ pub enum TableConstraint {
398
399
referred_columns : Vec < Ident > ,
399
400
on_delete : Option < ReferentialAction > ,
400
401
on_update : Option < ReferentialAction > ,
402
+ characteristics : Option < ConstraintCharacteristics > ,
401
403
} ,
402
404
/// `[ CONSTRAINT <name> ] CHECK (<expr>)`
403
405
Check {
@@ -454,20 +456,30 @@ impl fmt::Display for TableConstraint {
454
456
name,
455
457
columns,
456
458
is_primary,
457
- } => write ! (
458
- f,
459
- "{}{} ({})" ,
460
- display_constraint_name( name) ,
461
- if * is_primary { "PRIMARY KEY" } else { "UNIQUE" } ,
462
- display_comma_separated( columns)
463
- ) ,
459
+ characteristics,
460
+ } => {
461
+ write ! (
462
+ f,
463
+ "{}{} ({})" ,
464
+ display_constraint_name( name) ,
465
+ if * is_primary { "PRIMARY KEY" } else { "UNIQUE" } ,
466
+ display_comma_separated( columns)
467
+ ) ?;
468
+
469
+ if let Some ( characteristics) = characteristics {
470
+ write ! ( f, " {}" , characteristics) ?;
471
+ }
472
+
473
+ Ok ( ( ) )
474
+ }
464
475
TableConstraint :: ForeignKey {
465
476
name,
466
477
columns,
467
478
foreign_table,
468
479
referred_columns,
469
480
on_delete,
470
481
on_update,
482
+ characteristics,
471
483
} => {
472
484
write ! (
473
485
f,
@@ -483,6 +495,9 @@ impl fmt::Display for TableConstraint {
483
495
if let Some ( action) = on_update {
484
496
write ! ( f, " ON UPDATE {action}" ) ?;
485
497
}
498
+ if let Some ( characteristics) = characteristics {
499
+ write ! ( f, " {}" , characteristics) ?;
500
+ }
486
501
Ok ( ( ) )
487
502
}
488
503
TableConstraint :: Check { name, expr } => {
@@ -713,20 +728,24 @@ pub enum ColumnOption {
713
728
NotNull ,
714
729
/// `DEFAULT <restricted-expr>`
715
730
Default ( Expr ) ,
716
- /// `{ PRIMARY KEY | UNIQUE }`
731
+ /// `{ PRIMARY KEY | UNIQUE } [<constraint_characteristics>] `
717
732
Unique {
718
733
is_primary : bool ,
734
+ characteristics : Option < ConstraintCharacteristics > ,
719
735
} ,
720
736
/// A referential integrity constraint (`[FOREIGN KEY REFERENCES
721
737
/// <foreign_table> (<referred_columns>)
722
738
/// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
723
739
/// [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
724
- /// }`).
740
+ /// }
741
+ /// [<constraint_characteristics>]
742
+ /// `).
725
743
ForeignKey {
726
744
foreign_table : ObjectName ,
727
745
referred_columns : Vec < Ident > ,
728
746
on_delete : Option < ReferentialAction > ,
729
747
on_update : Option < ReferentialAction > ,
748
+ characteristics : Option < ConstraintCharacteristics > ,
730
749
} ,
731
750
/// `CHECK (<expr>)`
732
751
Check ( Expr ) ,
@@ -764,14 +783,22 @@ impl fmt::Display for ColumnOption {
764
783
Null => write ! ( f, "NULL" ) ,
765
784
NotNull => write ! ( f, "NOT NULL" ) ,
766
785
Default ( expr) => write ! ( f, "DEFAULT {expr}" ) ,
767
- Unique { is_primary } => {
768
- write ! ( f, "{}" , if * is_primary { "PRIMARY KEY" } else { "UNIQUE" } )
786
+ Unique {
787
+ is_primary,
788
+ characteristics,
789
+ } => {
790
+ write ! ( f, "{}" , if * is_primary { "PRIMARY KEY" } else { "UNIQUE" } ) ?;
791
+ if let Some ( characteristics) = characteristics {
792
+ write ! ( f, " {}" , characteristics) ?;
793
+ }
794
+ Ok ( ( ) )
769
795
}
770
796
ForeignKey {
771
797
foreign_table,
772
798
referred_columns,
773
799
on_delete,
774
800
on_update,
801
+ characteristics,
775
802
} => {
776
803
write ! ( f, "REFERENCES {foreign_table}" ) ?;
777
804
if !referred_columns. is_empty ( ) {
@@ -783,6 +810,9 @@ impl fmt::Display for ColumnOption {
783
810
if let Some ( action) = on_update {
784
811
write ! ( f, " ON UPDATE {action}" ) ?;
785
812
}
813
+ if let Some ( characteristics) = characteristics {
814
+ write ! ( f, " {}" , characteristics) ?;
815
+ }
786
816
Ok ( ( ) )
787
817
}
788
818
Check ( expr) => write ! ( f, "CHECK ({expr})" ) ,
@@ -874,6 +904,84 @@ fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
874
904
ConstraintName ( name)
875
905
}
876
906
907
+ /// `<constraint_characteristics> = [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ]`
908
+ ///
909
+ /// Used in UNIQUE and foreign key constraints. The individual settings may occur in any order.
910
+ #[ derive( Debug , Copy , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
911
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
912
+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
913
+ pub struct ConstraintCharacteristics {
914
+ /// `[ DEFERRABLE | NOT DEFERRABLE ]`
915
+ pub deferrable : Option < bool > ,
916
+ /// `[ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]`
917
+ pub initially : Option < DeferrableInitial > ,
918
+ /// `[ ENFORCED | NOT ENFORCED ]`
919
+ pub enforced : Option < bool > ,
920
+ }
921
+
922
+ #[ derive( Debug , Copy , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
923
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
924
+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
925
+ pub enum DeferrableInitial {
926
+ /// `INITIALLY IMMEDIATE`
927
+ Immediate ,
928
+ /// `INITIALLY DEFERRED`
929
+ Deferred ,
930
+ }
931
+
932
+ impl ConstraintCharacteristics {
933
+ fn deferrable_text ( & self ) -> Option < & ' static str > {
934
+ self . deferrable . map ( |deferrable| {
935
+ if deferrable {
936
+ "DEFERRABLE"
937
+ } else {
938
+ "NOT DEFERRABLE"
939
+ }
940
+ } )
941
+ }
942
+
943
+ fn initially_immediate_text ( & self ) -> Option < & ' static str > {
944
+ self . initially
945
+ . map ( |initially_immediate| match initially_immediate {
946
+ DeferrableInitial :: Immediate => "INITIALLY IMMEDIATE" ,
947
+ DeferrableInitial :: Deferred => "INITIALLY DEFERRED" ,
948
+ } )
949
+ }
950
+
951
+ fn enforced_text ( & self ) -> Option < & ' static str > {
952
+ self . enforced . map (
953
+ |enforced| {
954
+ if enforced {
955
+ "ENFORCED"
956
+ } else {
957
+ "NOT ENFORCED"
958
+ }
959
+ } ,
960
+ )
961
+ }
962
+ }
963
+
964
+ impl fmt:: Display for ConstraintCharacteristics {
965
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
966
+ let deferrable = self . deferrable_text ( ) ;
967
+ let initially_immediate = self . initially_immediate_text ( ) ;
968
+ let enforced = self . enforced_text ( ) ;
969
+
970
+ match ( deferrable, initially_immediate, enforced) {
971
+ ( None , None , None ) => Ok ( ( ) ) ,
972
+ ( None , None , Some ( enforced) ) => write ! ( f, "{enforced}" ) ,
973
+ ( None , Some ( initial) , None ) => write ! ( f, "{initial}" ) ,
974
+ ( None , Some ( initial) , Some ( enforced) ) => write ! ( f, "{initial} {enforced}" ) ,
975
+ ( Some ( deferrable) , None , None ) => write ! ( f, "{deferrable}" ) ,
976
+ ( Some ( deferrable) , None , Some ( enforced) ) => write ! ( f, "{deferrable} {enforced}" ) ,
977
+ ( Some ( deferrable) , Some ( initial) , None ) => write ! ( f, "{deferrable} {initial}" ) ,
978
+ ( Some ( deferrable) , Some ( initial) , Some ( enforced) ) => {
979
+ write ! ( f, "{deferrable} {initial} {enforced}" )
980
+ }
981
+ }
982
+ }
983
+ }
984
+
877
985
/// `<referential_action> =
878
986
/// { RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT }`
879
987
///
0 commit comments