@@ -276,6 +276,8 @@ static void AlterIndexNamespaces(Relation classRel, Relation rel,
276
276
static void AlterSeqNamespaces (Relation classRel , Relation rel ,
277
277
Oid oldNspOid , Oid newNspOid , ObjectAddresses * objsMoved ,
278
278
LOCKMODE lockmode );
279
+ static void ATExecAlterConstraint (Relation rel , AlterTableCmd * cmd ,
280
+ bool recurse , bool recursing , LOCKMODE lockmode );
279
281
static void ATExecValidateConstraint (Relation rel , char * constrName ,
280
282
bool recurse , bool recursing , LOCKMODE lockmode );
281
283
static int transformColumnNameList (Oid relId , List * colList ,
@@ -2887,6 +2889,7 @@ AlterTableGetLockLevel(List *cmds)
2887
2889
case AT_SetOptions :
2888
2890
case AT_ResetOptions :
2889
2891
case AT_SetStorage :
2892
+ case AT_AlterConstraint :
2890
2893
case AT_ValidateConstraint :
2891
2894
cmd_lockmode = ShareUpdateExclusiveLock ;
2892
2895
break ;
@@ -3125,6 +3128,10 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
3125
3128
ATPrepAddInherit (rel );
3126
3129
pass = AT_PASS_MISC ;
3127
3130
break ;
3131
+ case AT_AlterConstraint : /* ALTER CONSTRAINT */
3132
+ ATSimplePermissions (rel , ATT_TABLE );
3133
+ pass = AT_PASS_MISC ;
3134
+ break ;
3128
3135
case AT_ValidateConstraint : /* VALIDATE CONSTRAINT */
3129
3136
ATSimplePermissions (rel , ATT_TABLE );
3130
3137
/* Recursion occurs during execution phase */
@@ -3304,6 +3311,9 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
3304
3311
case AT_AddIndexConstraint : /* ADD CONSTRAINT USING INDEX */
3305
3312
ATExecAddIndexConstraint (tab , rel , (IndexStmt * ) cmd -> def , lockmode );
3306
3313
break ;
3314
+ case AT_AlterConstraint : /* ALTER CONSTRAINT */
3315
+ ATExecAlterConstraint (rel , cmd , false, false, lockmode );
3316
+ break ;
3307
3317
case AT_ValidateConstraint : /* VALIDATE CONSTRAINT */
3308
3318
ATExecValidateConstraint (rel , cmd -> name , false, false, lockmode );
3309
3319
break ;
@@ -6175,6 +6185,135 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
6175
6185
heap_close (pkrel , NoLock );
6176
6186
}
6177
6187
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
+
6178
6317
/*
6179
6318
* ALTER TABLE VALIDATE CONSTRAINT
6180
6319
*
0 commit comments