ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd,
						 bool recurse, bool recursing, LOCKMODE lockmode)
{
	Relation	conrel;
	SysScanDesc scan;
	ScanKeyData key;
	HeapTuple	contuple;
	Form_pg_constraint currcon = NULL;
	Constraint	*cmdcon = NULL;
	bool		found = false;

	Assert(IsA(cmd->def, Constraint));
	cmdcon = (Constraint *) cmd->def;

	conrel = heap_open(ConstraintRelationId, RowExclusiveLock);

	/*
	 * Find and check the target constraint
	 */
	ScanKeyInit(&key,
				Anum_pg_constraint_conrelid,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(RelationGetRelid(rel)));
	scan = systable_beginscan(conrel, ConstraintRelidIndexId,
							  true, NULL, 1, &key);

	while (HeapTupleIsValid(contuple = systable_getnext(scan)))
	{
		currcon = (Form_pg_constraint) GETSTRUCT(contuple);
		if (strcmp(NameStr(currcon->conname), cmdcon->conname) == 0)
		{
			found = true;
			break;
		}
	}

	if (!found)
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
						cmdcon->conname, RelationGetRelationName(rel))));

	if (currcon->contype != CONSTRAINT_FOREIGN)
		ereport(ERROR,
				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
				 errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key constraint",
						cmdcon->conname, RelationGetRelationName(rel))));

	if (currcon->condeferrable != cmdcon->deferrable ||
		currcon->condeferred != cmdcon->initdeferred)
	{
		HeapTuple	copyTuple;
		HeapTuple	tgtuple;
		Form_pg_constraint copy_con;
		Form_pg_trigger copy_tg;
		ScanKeyData tgkey;
		SysScanDesc tgscan;
		Relation	tgrel;

		/*
		 * Now update the catalog, while we have the door open.
		 */
		copyTuple = heap_copytuple(contuple);
		copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
		copy_con->condeferrable = cmdcon->deferrable;
		copy_con->condeferred = cmdcon->initdeferred;
		simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
		CatalogUpdateIndexes(conrel, copyTuple);

		InvokeObjectPostAlterHook(ConstraintRelationId,
								  HeapTupleGetOid(contuple), 0);

		heap_freetuple(copyTuple);

		/*
		 * Now we need to update the multiple entries in pg_trigger
		 * that implement the constraint.
		 */
		tgrel = heap_open(TriggerRelationId, RowExclusiveLock);

		ScanKeyInit(&tgkey,
					Anum_pg_trigger_tgconstraint,
					BTEqualStrategyNumber, F_OIDEQ,
					ObjectIdGetDatum(HeapTupleGetOid(contuple)));

		tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
									NULL, 1, &tgkey);

		while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan)))
		{
			copyTuple = heap_copytuple(tgtuple);
			copy_tg = (Form_pg_trigger) GETSTRUCT(copyTuple);
			copy_tg->tgdeferrable = cmdcon->deferrable;
			copy_tg->tginitdeferred = cmdcon->initdeferred;
			simple_heap_update(tgrel, &copyTuple->t_self, copyTuple);
			CatalogUpdateIndexes(tgrel, copyTuple);

			InvokeObjectPostAlterHook(TriggerRelationId,
										HeapTupleGetOid(tgtuple), 0);

			heap_freetuple(copyTuple);
		}

		systable_endscan(tgscan);

		heap_close(tgrel, RowExclusiveLock);

		/*
		 * Invalidate relcache so that others see the new attributes.
		 */
		CacheInvalidateRelcache(rel);
	}

	systable_endscan(scan);

	heap_close(conrel, RowExclusiveLock);
}