@@ -275,6 +275,8 @@ static void AlterIndexNamespaces(Relation classRel, Relation rel,
275275static void AlterSeqNamespaces (Relation classRel , Relation rel ,
276276 Oid oldNspOid , Oid newNspOid , ObjectAddresses * objsMoved ,
277277 LOCKMODE lockmode );
278+ static void ATExecAlterConstraint (Relation rel , AlterTableCmd * cmd ,
279+ bool recurse , bool recursing , LOCKMODE lockmode );
278280static void ATExecValidateConstraint (Relation rel , char * constrName ,
279281 bool recurse , bool recursing , LOCKMODE lockmode );
280282static int transformColumnNameList (Oid relId , List * colList ,
@@ -2886,6 +2888,7 @@ AlterTableGetLockLevel(List *cmds)
28862888 case AT_SetOptions :
28872889 case AT_ResetOptions :
28882890 case AT_SetStorage :
2891+ case AT_AlterConstraint :
28892892 case AT_ValidateConstraint :
28902893 cmd_lockmode = ShareUpdateExclusiveLock ;
28912894 break ;
@@ -3124,6 +3127,9 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
31243127 ATPrepAddInherit (rel );
31253128 pass = AT_PASS_MISC ;
31263129 break ;
3130+ case AT_AlterConstraint : /* ALTER CONSTRAINT */
3131+ ATSimplePermissions (rel , ATT_TABLE );
3132+ break ;
31273133 case AT_ValidateConstraint : /* VALIDATE CONSTRAINT */
31283134 ATSimplePermissions (rel , ATT_TABLE );
31293135 /* Recursion occurs during execution phase */
@@ -3302,6 +3308,9 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
33023308 case AT_AddIndexConstraint : /* ADD CONSTRAINT USING INDEX */
33033309 ATExecAddIndexConstraint (tab , rel , (IndexStmt * ) cmd -> def , lockmode );
33043310 break ;
3311+ case AT_AlterConstraint : /* ALTER CONSTRAINT */
3312+ ATExecAlterConstraint (rel , cmd , false, false, lockmode );
3313+ break ;
33053314 case AT_ValidateConstraint : /* VALIDATE CONSTRAINT */
33063315 ATExecValidateConstraint (rel , cmd -> name , false, false, lockmode );
33073316 break ;
@@ -6173,6 +6182,135 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
61736182 heap_close (pkrel , NoLock );
61746183}
61756184
6185+ /*
6186+ * ALTER TABLE ALTER CONSTRAINT
6187+ *
6188+ * Update the attributes of a constraint.
6189+ *
6190+ * Currently only works for Foreign Key constraints.
6191+ * Foreign keys do not inherit, so we purposely ignore the
6192+ * recursion bit here, but we keep the API the same for when
6193+ * other constraint types are supported.
6194+ */
6195+ static void
6196+ ATExecAlterConstraint (Relation rel , AlterTableCmd * cmd ,
6197+ bool recurse , bool recursing , LOCKMODE lockmode )
6198+ {
6199+ Relation conrel ;
6200+ SysScanDesc scan ;
6201+ ScanKeyData key ;
6202+ HeapTuple contuple ;
6203+ Form_pg_constraint currcon = NULL ;
6204+ Constraint * cmdcon = NULL ;
6205+ bool found = false;
6206+
6207+ Assert (IsA (cmd -> def , Constraint ));
6208+ cmdcon = (Constraint * ) cmd -> def ;
6209+
6210+ conrel = heap_open (ConstraintRelationId , RowExclusiveLock );
6211+
6212+ /*
6213+ * Find and check the target constraint
6214+ */
6215+ ScanKeyInit (& key ,
6216+ Anum_pg_constraint_conrelid ,
6217+ BTEqualStrategyNumber , F_OIDEQ ,
6218+ ObjectIdGetDatum (RelationGetRelid (rel )));
6219+ scan = systable_beginscan (conrel , ConstraintRelidIndexId ,
6220+ true, SnapshotNow , 1 , & key );
6221+
6222+ while (HeapTupleIsValid (contuple = systable_getnext (scan )))
6223+ {
6224+ currcon = (Form_pg_constraint ) GETSTRUCT (contuple );
6225+ if (strcmp (NameStr (currcon -> conname ), cmdcon -> conname ) == 0 )
6226+ {
6227+ found = true;
6228+ break ;
6229+ }
6230+ }
6231+
6232+ if (!found )
6233+ ereport (ERROR ,
6234+ (errcode (ERRCODE_UNDEFINED_OBJECT ),
6235+ errmsg ("constraint \"%s\" of relation \"%s\" does not exist" ,
6236+ cmdcon -> conname , RelationGetRelationName (rel ))));
6237+
6238+ if (currcon -> contype != CONSTRAINT_FOREIGN )
6239+ ereport (ERROR ,
6240+ (errcode (ERRCODE_WRONG_OBJECT_TYPE ),
6241+ errmsg ("constraint \"%s\" of relation \"%s\" is not a foreign key constraint" ,
6242+ cmdcon -> conname , RelationGetRelationName (rel ))));
6243+
6244+ if (currcon -> condeferrable != cmdcon -> deferrable ||
6245+ currcon -> condeferred != cmdcon -> initdeferred )
6246+ {
6247+ HeapTuple copyTuple ;
6248+ HeapTuple tgtuple ;
6249+ Form_pg_constraint copy_con ;
6250+ Form_pg_trigger copy_tg ;
6251+ ScanKeyData tgkey ;
6252+ SysScanDesc tgscan ;
6253+ Relation tgrel ;
6254+
6255+ /*
6256+ * Now update the catalog, while we have the door open.
6257+ */
6258+ copyTuple = heap_copytuple (contuple );
6259+ copy_con = (Form_pg_constraint ) GETSTRUCT (copyTuple );
6260+ copy_con -> condeferrable = cmdcon -> deferrable ;
6261+ copy_con -> condeferred = cmdcon -> initdeferred ;
6262+ simple_heap_update (conrel , & copyTuple -> t_self , copyTuple );
6263+ CatalogUpdateIndexes (conrel , copyTuple );
6264+
6265+ InvokeObjectPostAlterHook (ConstraintRelationId ,
6266+ HeapTupleGetOid (contuple ), 0 );
6267+
6268+ heap_freetuple (copyTuple );
6269+
6270+ /*
6271+ * Now we need to update the multiple entries in pg_trigger
6272+ * that implement the constraint.
6273+ */
6274+ tgrel = heap_open (TriggerRelationId , RowExclusiveLock );
6275+
6276+ ScanKeyInit (& tgkey ,
6277+ Anum_pg_trigger_tgconstraint ,
6278+ BTEqualStrategyNumber , F_OIDEQ ,
6279+ ObjectIdGetDatum (HeapTupleGetOid (contuple )));
6280+
6281+ tgscan = systable_beginscan (tgrel , TriggerConstraintIndexId , true,
6282+ SnapshotNow , 1 , & tgkey );
6283+
6284+ while (HeapTupleIsValid (tgtuple = systable_getnext (tgscan )))
6285+ {
6286+ copyTuple = heap_copytuple (tgtuple );
6287+ copy_tg = (Form_pg_trigger ) GETSTRUCT (copyTuple );
6288+ copy_tg -> tgdeferrable = cmdcon -> deferrable ;
6289+ copy_tg -> tginitdeferred = cmdcon -> initdeferred ;
6290+ simple_heap_update (tgrel , & copyTuple -> t_self , copyTuple );
6291+ CatalogUpdateIndexes (tgrel , copyTuple );
6292+
6293+ InvokeObjectPostAlterHook (TriggerRelationId ,
6294+ HeapTupleGetOid (tgtuple ), 0 );
6295+
6296+ heap_freetuple (copyTuple );
6297+ }
6298+
6299+ systable_endscan (tgscan );
6300+
6301+ heap_close (tgrel , RowExclusiveLock );
6302+
6303+ /*
6304+ * Invalidate relcache so that others see the new attributes.
6305+ */
6306+ CacheInvalidateRelcache (rel );
6307+ }
6308+
6309+ systable_endscan (scan );
6310+
6311+ heap_close (conrel , RowExclusiveLock );
6312+ }
6313+
61766314/*
61776315 * ALTER TABLE VALIDATE CONSTRAINT
61786316 *
0 commit comments