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