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