@@ -385,6 +385,7 @@ pub enum TableConstraint {
385385 columns : Vec < Ident > ,
386386 /// Whether this is a `PRIMARY KEY` or just a `UNIQUE` constraint
387387 is_primary : bool ,
388+ characteristics : Option < ConstraintCharacteristics > ,
388389 } ,
389390 /// A referential integrity constraint (`[ CONSTRAINT <name> ] FOREIGN KEY (<columns>)
390391 /// REFERENCES <foreign_table> (<referred_columns>)
@@ -398,6 +399,7 @@ pub enum TableConstraint {
398399 referred_columns : Vec < Ident > ,
399400 on_delete : Option < ReferentialAction > ,
400401 on_update : Option < ReferentialAction > ,
402+ characteristics : Option < ConstraintCharacteristics > ,
401403 } ,
402404 /// `[ CONSTRAINT <name> ] CHECK (<expr>)`
403405 Check {
@@ -454,20 +456,30 @@ impl fmt::Display for TableConstraint {
454456 name,
455457 columns,
456458 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+ }
464475 TableConstraint :: ForeignKey {
465476 name,
466477 columns,
467478 foreign_table,
468479 referred_columns,
469480 on_delete,
470481 on_update,
482+ characteristics,
471483 } => {
472484 write ! (
473485 f,
@@ -483,6 +495,9 @@ impl fmt::Display for TableConstraint {
483495 if let Some ( action) = on_update {
484496 write ! ( f, " ON UPDATE {action}" ) ?;
485497 }
498+ if let Some ( characteristics) = characteristics {
499+ write ! ( f, " {}" , characteristics) ?;
500+ }
486501 Ok ( ( ) )
487502 }
488503 TableConstraint :: Check { name, expr } => {
@@ -713,20 +728,24 @@ pub enum ColumnOption {
713728 NotNull ,
714729 /// `DEFAULT <restricted-expr>`
715730 Default ( Expr ) ,
716- /// `{ PRIMARY KEY | UNIQUE }`
731+ /// `{ PRIMARY KEY | UNIQUE } [<constraint_characteristics>] `
717732 Unique {
718733 is_primary : bool ,
734+ characteristics : Option < ConstraintCharacteristics > ,
719735 } ,
720736 /// A referential integrity constraint (`[FOREIGN KEY REFERENCES
721737 /// <foreign_table> (<referred_columns>)
722738 /// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
723739 /// [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
724- /// }`).
740+ /// }
741+ /// [<constraint_characteristics>]
742+ /// `).
725743 ForeignKey {
726744 foreign_table : ObjectName ,
727745 referred_columns : Vec < Ident > ,
728746 on_delete : Option < ReferentialAction > ,
729747 on_update : Option < ReferentialAction > ,
748+ characteristics : Option < ConstraintCharacteristics > ,
730749 } ,
731750 /// `CHECK (<expr>)`
732751 Check ( Expr ) ,
@@ -764,14 +783,22 @@ impl fmt::Display for ColumnOption {
764783 Null => write ! ( f, "NULL" ) ,
765784 NotNull => write ! ( f, "NOT NULL" ) ,
766785 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 ( ( ) )
769795 }
770796 ForeignKey {
771797 foreign_table,
772798 referred_columns,
773799 on_delete,
774800 on_update,
801+ characteristics,
775802 } => {
776803 write ! ( f, "REFERENCES {foreign_table}" ) ?;
777804 if !referred_columns. is_empty ( ) {
@@ -783,6 +810,9 @@ impl fmt::Display for ColumnOption {
783810 if let Some ( action) = on_update {
784811 write ! ( f, " ON UPDATE {action}" ) ?;
785812 }
813+ if let Some ( characteristics) = characteristics {
814+ write ! ( f, " {}" , characteristics) ?;
815+ }
786816 Ok ( ( ) )
787817 }
788818 Check ( expr) => write ! ( f, "CHECK ({expr})" ) ,
@@ -874,6 +904,84 @@ fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
874904 ConstraintName ( name)
875905}
876906
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+
877985/// `<referential_action> =
878986/// { RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT }`
879987///
0 commit comments