diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index c54104200d7eaf4b5b363a48a8a154ca6e25ed6c..4335792ee712dc82658ec48a160e1eb17a2a2437 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.158 2005/05/30 06:52:38 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.159 2005/05/30 07:20:58 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -156,12 +156,6 @@ typedef struct NewColumnValue
 } NewColumnValue;
 
 
-/* Used by attribute and relation renaming routines: */
-#define RI_TRIGGER_PK	1		/* is a trigger on the PK relation */
-#define RI_TRIGGER_FK	2		/* is a trigger on the FK relation */
-#define RI_TRIGGER_NONE 0		/* is not an RI trigger function */
-
-
 static List *MergeAttributes(List *schema, List *supers, bool istemp,
 				List **supOids, List **supconstr, int *supOidCount);
 static bool change_varattnos_of_a_node(Node *node, const AttrNumber *newattno);
@@ -246,7 +240,6 @@ static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
 					char *tablespacename);
 static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace);
 static void copy_relation_data(Relation rel, SMgrRelation dst);
-static int	ri_trigger_type(Oid tgfoid);
 static void update_ri_trigger_args(Oid relid,
 					   const char *oldname,
 					   const char *newname,
@@ -1571,39 +1564,6 @@ renamerel(Oid myrelid, const char *newrelname)
 	relation_close(targetrelation, NoLock);
 }
 
-
-/*
- * Given a trigger function OID, determine whether it is an RI trigger,
- * and if so whether it is attached to PK or FK relation.
- *
- * XXX this probably doesn't belong here; should be exported by
- * ri_triggers.c
- */
-static int
-ri_trigger_type(Oid tgfoid)
-{
-	switch (tgfoid)
-	{
-		case F_RI_FKEY_CASCADE_DEL:
-		case F_RI_FKEY_CASCADE_UPD:
-		case F_RI_FKEY_RESTRICT_DEL:
-		case F_RI_FKEY_RESTRICT_UPD:
-		case F_RI_FKEY_SETNULL_DEL:
-		case F_RI_FKEY_SETNULL_UPD:
-		case F_RI_FKEY_SETDEFAULT_DEL:
-		case F_RI_FKEY_SETDEFAULT_UPD:
-		case F_RI_FKEY_NOACTION_DEL:
-		case F_RI_FKEY_NOACTION_UPD:
-			return RI_TRIGGER_PK;
-
-		case F_RI_FKEY_CHECK_INS:
-		case F_RI_FKEY_CHECK_UPD:
-			return RI_TRIGGER_FK;
-	}
-
-	return RI_TRIGGER_NONE;
-}
-
 /*
  * Scan pg_trigger for RI triggers that are on the specified relation
  * (if fk_scan is false) or have it as the tgconstrrel (if fk_scan
@@ -1663,7 +1623,7 @@ update_ri_trigger_args(Oid relid,
 		const char *arga[RI_MAX_ARGUMENTS];
 		const char *argp;
 
-		tg_type = ri_trigger_type(pg_trigger->tgfoid);
+		tg_type = RI_FKey_trigger_type(pg_trigger->tgfoid);
 		if (tg_type == RI_TRIGGER_NONE)
 		{
 			/* Not an RI trigger, forget it */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index a78ad890b3c84ee0252b4318cf56c70ec6c329f5..e0cfd33485547230eb987259370e45a90fe3b6b8 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.188 2005/05/06 17:24:53 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.189 2005/05/30 07:20:58 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2994,54 +2994,47 @@ AfterTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger,
 			continue;
 
 		/*
-		 * If it is an RI UPDATE trigger, and the referenced keys have
-		 * not changed, short-circuit queuing of the event; there's no
-		 * need to fire the trigger.
+		 * If this is an UPDATE of a PK table or FK table that does
+		 * not change the PK or FK respectively, we can skip queuing
+		 * the event: there is no need to fire the trigger.
 		 */
 		if ((event & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_UPDATE)
 		{
-			bool		is_ri_trigger;
-
-			switch (trigger->tgfoid)
+			switch (RI_FKey_trigger_type(trigger->tgfoid))
 			{
-				case F_RI_FKEY_NOACTION_UPD:
-				case F_RI_FKEY_CASCADE_UPD:
-				case F_RI_FKEY_RESTRICT_UPD:
-				case F_RI_FKEY_SETNULL_UPD:
-				case F_RI_FKEY_SETDEFAULT_UPD:
-					is_ri_trigger = true;
+				case RI_TRIGGER_PK:
+					/* Update on PK table */
+					if (RI_FKey_keyequal_upd_pk(trigger, rel, oldtup, newtup))
+					{
+						/* key unchanged, so skip queuing this event */
+						continue;
+					}
 					break;
 
-				default:
-					is_ri_trigger = false;
+				case RI_TRIGGER_FK:
+					/*
+					 * Update on FK table
+					 *
+					 * There is one exception when updating FK tables:
+					 * if the updated row was inserted by our own
+					 * transaction and the FK is deferred, we still
+					 * need to fire the trigger. This is because our
+					 * UPDATE will invalidate the INSERT so the
+					 * end-of-transaction INSERT RI trigger will not
+					 * do anything, so we have to do the check for the
+					 * UPDATE anyway.
+					 */
+					if (HeapTupleHeaderGetXmin(oldtup->t_data) !=
+						GetCurrentTransactionId() &&
+						RI_FKey_keyequal_upd_fk(trigger, rel, oldtup, newtup))
+					{
+						continue;
+					}
 					break;
-			}
 
-			if (is_ri_trigger)
-			{
-				TriggerData LocTriggerData;
-
-				LocTriggerData.type = T_TriggerData;
-				LocTriggerData.tg_event =
-					TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW;
-				LocTriggerData.tg_relation = rel;
-				LocTriggerData.tg_trigtuple = oldtup;
-				LocTriggerData.tg_newtuple = newtup;
-				LocTriggerData.tg_trigger = trigger;
-				/*
-				 * We do not currently know which buffers the passed tuples
-				 * are in, but it does not matter because RI_FKey_keyequal_upd
-				 * does not care.  We could expand the API of this function
-				 * if it becomes necessary to set these fields accurately.
-				 */
-				LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
-				LocTriggerData.tg_newtuplebuf = InvalidBuffer;
-
-				if (RI_FKey_keyequal_upd(&LocTriggerData))
-				{
-					/* key unchanged, so skip queuing this event */
-					continue;
-				}
+				case RI_TRIGGER_NONE:
+					/* Not an FK trigger */
+					break;
 			}
 		}
 
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 0dc1241012434ca02edfe3960ed965a673163124..a0d561f1f0f53ecd9a0a67b5944185f9ef537cd5 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -17,7 +17,7 @@
  *
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.78 2005/05/29 04:23:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.79 2005/05/30 07:20:58 neilc Exp $
  *
  * ----------
  */
@@ -38,10 +38,11 @@
 #include "optimizer/planmain.h"
 #include "parser/parse_oper.h"
 #include "rewrite/rewriteHandler.h"
-#include "utils/lsyscache.h"
-#include "utils/typcache.h"
 #include "utils/acl.h"
+#include "utils/fmgroids.h"
 #include "utils/guc.h"
+#include "utils/lsyscache.h"
+#include "utils/typcache.h"
 #include "miscadmin.h"
 
 
@@ -375,22 +376,6 @@ RI_FKey_check(PG_FUNCTION_ARGS)
 			break;
 	}
 
-	/*
-	 * No need to check anything if old and new references are the same on
-	 * UPDATE.
-	 */
-	if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
-	{
-		if (HeapTupleHeaderGetXmin(old_row->t_data) !=
-			GetCurrentTransactionId() &&
-			ri_KeysEqual(fk_rel, old_row, new_row, &qkey,
-						 RI_KEYPAIR_FK_IDX))
-		{
-			heap_close(pk_rel, RowShareLock);
-			return PointerGetDatum(NULL);
-		}
-	}
-
 	if (SPI_connect() != SPI_OK_CONNECT)
 		elog(ERROR, "SPI_connect failed");
 
@@ -2005,8 +1990,8 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
 					 * corresponding to changed columns in pk_rel's key
 					 */
 					if (match_type == RI_MATCH_TYPE_FULL ||
-					  !ri_OneKeyEqual(pk_rel, i, old_row, new_row, &qkey,
-									  RI_KEYPAIR_PK_IDX))
+						!ri_OneKeyEqual(pk_rel, i, old_row, new_row, &qkey,
+										RI_KEYPAIR_PK_IDX))
 					{
 						snprintf(querystr + strlen(querystr), sizeof(querystr) - strlen(querystr), "%s %s = NULL",
 								 querysep, attname);
@@ -2016,7 +2001,7 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
 							 qualsep, attname, i + 1);
 					qualsep = "AND";
 					queryoids[i] = SPI_gettypeid(pk_rel->rd_att,
-									 qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
+												 qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
 				}
 				strcat(querystr, qualstr);
 
@@ -2451,30 +2436,27 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
 
 
 /* ----------
- * RI_FKey_keyequal_upd -
- *
- *	Check if we have a key change on update.
+ * RI_FKey_keyequal_upd_pk -
  *
- *	This is not a real trigger procedure. It is used by the AFTER
- *	trigger queue manager to detect "triggered data change violation".
+ *	Check if we have a key change on an update to a PK relation. This is
+ *	used by the AFTER trigger queue manager to detect "triggered data
+ *	change violation".
  * ----------
  */
 bool
-RI_FKey_keyequal_upd(TriggerData *trigdata)
+RI_FKey_keyequal_upd_pk(Trigger *trigger, Relation pk_rel,
+						HeapTuple old_row, HeapTuple new_row)
 {
 	int			tgnargs;
 	char	  **tgargs;
 	Relation	fk_rel;
-	Relation	pk_rel;
-	HeapTuple	new_row;
-	HeapTuple	old_row;
 	RI_QueryKey qkey;
 
 	/*
 	 * Check for the correct # of call arguments
 	 */
-	tgnargs = trigdata->tg_trigger->tgnargs;
-	tgargs = trigdata->tg_trigger->tgargs;
+	tgnargs = trigger->tgnargs;
+	tgargs = trigger->tgargs;
 	if (tgnargs < 4 ||
 		tgnargs > RI_MAX_ARGUMENTS ||
 		(tgnargs % 2) != 0)
@@ -2489,48 +2471,32 @@ RI_FKey_keyequal_upd(TriggerData *trigdata)
 	if (tgnargs == 4)
 		return true;
 
-	/*
-	 * Get the relation descriptors of the FK and PK tables and the new
-	 * and old tuple.
-	 *
-	 * Use minimal locking for fk_rel here.
-	 */
-	if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
+	if (!OidIsValid(trigger->tgconstrrelid))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-		errmsg("no target table given for trigger \"%s\" on table \"%s\"",
-			   trigdata->tg_trigger->tgname,
-			   RelationGetRelationName(trigdata->tg_relation)),
-				 errhint("Remove this referential integrity trigger and its mates, then do ALTER TABLE ADD CONSTRAINT.")));
+				 errmsg("no target table given for trigger \"%s\" on table \"%s\"",
+						trigger->tgname,
+						RelationGetRelationName(pk_rel)),
+				 errhint("Remove this referential integrity trigger and its mates, "
+						 "then do ALTER TABLE ADD CONSTRAINT.")));
 
-	fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, AccessShareLock);
-	pk_rel = trigdata->tg_relation;
-	new_row = trigdata->tg_newtuple;
-	old_row = trigdata->tg_trigtuple;
+	fk_rel = heap_open(trigger->tgconstrrelid, AccessShareLock);
 
 	switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]))
 	{
-			/*
-			 * MATCH <UNSPECIFIED>
-			 */
 		case RI_MATCH_TYPE_UNSPECIFIED:
 		case RI_MATCH_TYPE_FULL:
-			ri_BuildQueryKeyFull(&qkey, trigdata->tg_trigger->tgoid,
+			ri_BuildQueryKeyFull(&qkey, trigger->tgoid,
 								 RI_PLAN_KEYEQUAL_UPD,
 								 fk_rel, pk_rel,
 								 tgnargs, tgargs);
-
 			heap_close(fk_rel, AccessShareLock);
 
-			/*
-			 * Return if key's are equal
-			 */
+			/* Return if key's are equal */
 			return ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
 								RI_KEYPAIR_PK_IDX);
 
-			/*
-			 * Handle MATCH PARTIAL set null delete.
-			 */
+		/* Handle MATCH PARTIAL set null delete. */
 		case RI_MATCH_TYPE_PARTIAL:
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -2538,14 +2504,85 @@ RI_FKey_keyequal_upd(TriggerData *trigdata)
 			break;
 	}
 
+	/* Never reached */
+	elog(ERROR, "invalid match_type");
+	return false;
+}
+
+/* ----------
+ * RI_FKey_keyequal_upd_fk -
+ *
+ *	Check if we have a key change on an update to an FK relation. This is
+ *	used by the AFTER trigger queue manager to detect "triggered data
+ *	change violation".
+ * ----------
+ */
+bool
+RI_FKey_keyequal_upd_fk(Trigger *trigger, Relation fk_rel,
+						HeapTuple old_row, HeapTuple new_row)
+{
+	int			tgnargs;
+	char	  **tgargs;
+	Relation	pk_rel;
+	RI_QueryKey qkey;
+
 	/*
-	 * Never reached
+	 * Check for the correct # of call arguments
 	 */
+	tgnargs = trigger->tgnargs;
+	tgargs = trigger->tgargs;
+	if (tgnargs < 4 ||
+		tgnargs > RI_MAX_ARGUMENTS ||
+		(tgnargs % 2) != 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
+				 errmsg("function \"%s\" called with wrong number of trigger arguments",
+						"RI_FKey_keyequal_upd")));
+
+	/*
+	 * Nothing to do if no column names to compare given
+	 */
+	if (tgnargs == 4)
+		return true;
+
+	if (!OidIsValid(trigger->tgconstrrelid))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+				 errmsg("no target table given for trigger \"%s\" on table \"%s\"",
+						trigger->tgname,
+						RelationGetRelationName(fk_rel)),
+				 errhint("Remove this referential integrity trigger and its mates, "
+						 "then do ALTER TABLE ADD CONSTRAINT.")));
+
+	pk_rel = heap_open(trigger->tgconstrrelid, AccessShareLock);
+
+	switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]))
+	{
+		case RI_MATCH_TYPE_UNSPECIFIED:
+		case RI_MATCH_TYPE_FULL:
+			ri_BuildQueryKeyFull(&qkey, trigger->tgoid,
+								 RI_PLAN_KEYEQUAL_UPD,
+								 fk_rel, pk_rel,
+								 tgnargs, tgargs);
+			heap_close(pk_rel, AccessShareLock);
+
+			/* Return if key's are equal */
+			return ri_KeysEqual(fk_rel, old_row, new_row, &qkey,
+								RI_KEYPAIR_FK_IDX);
+
+		/* Handle MATCH PARTIAL set null delete. */
+		case RI_MATCH_TYPE_PARTIAL:
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("MATCH PARTIAL not yet implemented")));
+			break;
+	}
+
+	/* Never reached */
 	elog(ERROR, "invalid match_type");
 	return false;
 }
 
-
 /* ----------
  * RI_Initial_Check -
  *
@@ -2871,7 +2908,7 @@ ri_BuildQueryKeyFull(RI_QueryKey *key, Oid constr_id, int32 constr_queryno,
 	/*
 	 * Initialize the key and fill in type, oid's and number of keypairs
 	 */
-	memset((void *) key, 0, sizeof(RI_QueryKey));
+	memset(key, 0, sizeof(RI_QueryKey));
 	key->constr_type = RI_MATCH_TYPE_FULL;
 	key->constr_id = constr_id;
 	key->constr_queryno = constr_queryno;
@@ -3489,7 +3526,7 @@ ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup,
 	for (i = 0; i < key->nkeypairs; i++)
 	{
 		/*
-		 * Get one attributes oldvalue. If it is NULL - they're not equal.
+		 * Get one attribute's oldvalue. If it is NULL - they're not equal.
 		 */
 		oldvalue = SPI_getbinval(oldtup, rel->rd_att,
 								 key->keypair[i][pairidx], &isnull);
@@ -3497,7 +3534,7 @@ ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup,
 			return false;
 
 		/*
-		 * Get one attributes oldvalue. If it is NULL - they're not equal.
+		 * Get one attribute's oldvalue. If it is NULL - they're not equal.
 		 */
 		newvalue = SPI_getbinval(newtup, rel->rd_att,
 								 key->keypair[i][pairidx], &isnull);
@@ -3505,7 +3542,7 @@ ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup,
 			return false;
 
 		/*
-		 * Get the attributes type OID and call the '=' operator to
+		 * Get the attribute's type OID and call the '=' operator to
 		 * compare the values.
 		 */
 		typeid = SPI_gettypeid(rel->rd_att, key->keypair[i][pairidx]);
@@ -3644,3 +3681,32 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
 	return DatumGetBool(FunctionCall2(&(typentry->eq_opr_finfo),
 									  oldvalue, newvalue));
 }
+
+/*
+ * Given a trigger function OID, determine whether it is an RI trigger,
+ * and if so whether it is attached to PK or FK relation.
+ */
+int
+RI_FKey_trigger_type(Oid tgfoid)
+{
+	switch (tgfoid)
+	{
+		case F_RI_FKEY_CASCADE_DEL:
+		case F_RI_FKEY_CASCADE_UPD:
+		case F_RI_FKEY_RESTRICT_DEL:
+		case F_RI_FKEY_RESTRICT_UPD:
+		case F_RI_FKEY_SETNULL_DEL:
+		case F_RI_FKEY_SETNULL_UPD:
+		case F_RI_FKEY_SETDEFAULT_DEL:
+		case F_RI_FKEY_SETDEFAULT_UPD:
+		case F_RI_FKEY_NOACTION_DEL:
+		case F_RI_FKEY_NOACTION_UPD:
+			return RI_TRIGGER_PK;
+
+		case F_RI_FKEY_CHECK_INS:
+		case F_RI_FKEY_CHECK_UPD:
+			return RI_TRIGGER_FK;
+	}
+
+	return RI_TRIGGER_NONE;
+}
diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h
index 81a665e24767e5f9b4d8fdecd5d554ddf2355690..f6c1f88480b96450ce724038c47657422a32f70b 100644
--- a/src/include/commands/trigger.h
+++ b/src/include/commands/trigger.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/trigger.h,v 1.53 2005/04/11 19:51:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/trigger.h,v 1.54 2005/05/30 07:20:58 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -168,9 +168,18 @@ extern void AfterTriggerSetState(ConstraintsSetStmt *stmt);
 /*
  * in utils/adt/ri_triggers.c
  */
-extern bool RI_FKey_keyequal_upd(TriggerData *trigdata);
+extern bool RI_FKey_keyequal_upd_pk(Trigger *trigger, Relation pk_rel,
+									HeapTuple old_row, HeapTuple new_row);
+extern bool RI_FKey_keyequal_upd_fk(Trigger *trigger, Relation fk_rel,
+									HeapTuple old_row, HeapTuple new_row);
 extern bool RI_Initial_Check(FkConstraint *fkconstraint,
 				 Relation rel,
 				 Relation pkrel);
 
+#define RI_TRIGGER_PK	1		/* is a trigger on the PK relation */
+#define RI_TRIGGER_FK	2		/* is a trigger on the FK relation */
+#define RI_TRIGGER_NONE 0		/* is not an RI trigger function */
+
+extern int RI_FKey_trigger_type(Oid tgfoid);
+
 #endif   /* TRIGGER_H */
diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out
index ae80b33c6f74b0f009b34a1b814f9f279b93d638..e3ea729e6fa92bd3c02d64c80ab3826e3edf47d7 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -1061,6 +1061,8 @@ INSERT INTO fktable VALUES (100, 200);
 COMMIT;
 ERROR:  insert or update on table "fktable" violates foreign key constraint "fktable_fk_fkey"
 DETAIL:  Key (fk)=(200) is not present in table "pktable".
+DROP TABLE pktable, fktable CASCADE;
+NOTICE:  drop cascades to constraint fktable_fk_fkey on table fktable
 -- test notice about expensive referential integrity checks,
 -- where the index cannot be used because of type incompatibilities.
 CREATE TEMP TABLE pktable (
@@ -1128,3 +1130,45 @@ WARNING:  foreign key constraint "fk_241_132" will require costly sequential sca
 DETAIL:  Key columns "x2" and "id1" are of different types: character varying and integer.
 WARNING:  foreign key constraint "fk_241_132" will require costly sequential scans
 DETAIL:  Key columns "x4" and "id3" are of different types: text and real.
+DROP TABLE pktable, fktable CASCADE;
+NOTICE:  drop cascades to constraint fk_241_132 on table fktable
+NOTICE:  drop cascades to constraint fk_123_231 on table fktable
+NOTICE:  drop cascades to constraint fk_253_213 on table fktable
+NOTICE:  drop cascades to constraint fk_213_213 on table fktable
+NOTICE:  drop cascades to constraint fk_123_123 on table fktable
+NOTICE:  drop cascades to constraint fk_5_1 on table fktable
+NOTICE:  drop cascades to constraint fk_3_1 on table fktable
+NOTICE:  drop cascades to constraint fk_2_1 on table fktable
+NOTICE:  drop cascades to constraint fktable_x1_fkey on table fktable
+NOTICE:  drop cascades to constraint fk_4_2 on table fktable
+NOTICE:  drop cascades to constraint fk_1_2 on table fktable
+NOTICE:  drop cascades to constraint fktable_x2_fkey on table fktable
+NOTICE:  drop cascades to constraint fk_1_3 on table fktable
+NOTICE:  drop cascades to constraint fk_2_3 on table fktable
+NOTICE:  drop cascades to constraint fktable_x3_fkey on table fktable
+-- test a tricky case: we can elide firing the FK check trigger during
+-- an UPDATE if the UPDATE did not change the foreign key
+-- field. However, we can't do this if our transaction was the one that
+-- created the updated row and the trigger is deferred, since our UPDATE
+-- will have invalidated the original newly-inserted tuple, and therefore
+-- cause the on-INSERT RI trigger not to be fired.
+CREATE TEMP TABLE pktable (
+    id int primary key,
+    other int
+);
+NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "pktable_pkey" for table "pktable"
+CREATE TEMP TABLE fktable (
+    id int primary key,
+    fk int references pktable deferrable initially deferred
+);
+NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "fktable_pkey" for table "fktable"
+INSERT INTO pktable VALUES (5, 10);
+BEGIN;
+-- doesn't match PK, but no error yet
+INSERT INTO fktable VALUES (0, 20);
+-- don't change FK
+UPDATE fktable SET id = id + 1;
+-- should catch error from initial INSERT
+COMMIT;
+ERROR:  insert or update on table "fktable" violates foreign key constraint "fktable_fk_fkey"
+DETAIL:  Key (fk)=(20) is not present in table "pktable".
diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql
index ad5865683fb252333735b8b1a1ed2430d5e161e1..5ab15c1b39be42af0d67afd0dd9eaf2a74644806 100644
--- a/src/test/regress/sql/foreign_key.sql
+++ b/src/test/regress/sql/foreign_key.sql
@@ -705,6 +705,8 @@ INSERT INTO fktable VALUES (100, 200);
 -- error here on commit
 COMMIT;
 
+DROP TABLE pktable, fktable CASCADE;
+
 -- test notice about expensive referential integrity checks,
 -- where the index cannot be used because of type incompatibilities.
 
@@ -774,3 +776,35 @@ FOREIGN KEY (x1,x2,x3) REFERENCES pktable(id2,id3,id1);
 
 ALTER TABLE fktable ADD CONSTRAINT fk_241_132
 FOREIGN KEY (x2,x4,x1) REFERENCES pktable(id1,id3,id2);
+
+DROP TABLE pktable, fktable CASCADE;
+
+-- test a tricky case: we can elide firing the FK check trigger during
+-- an UPDATE if the UPDATE did not change the foreign key
+-- field. However, we can't do this if our transaction was the one that
+-- created the updated row and the trigger is deferred, since our UPDATE
+-- will have invalidated the original newly-inserted tuple, and therefore
+-- cause the on-INSERT RI trigger not to be fired.
+
+CREATE TEMP TABLE pktable (
+    id int primary key,
+    other int
+);
+
+CREATE TEMP TABLE fktable (
+    id int primary key,
+    fk int references pktable deferrable initially deferred
+);
+
+INSERT INTO pktable VALUES (5, 10);
+
+BEGIN;
+
+-- doesn't match PK, but no error yet
+INSERT INTO fktable VALUES (0, 20);
+
+-- don't change FK
+UPDATE fktable SET id = id + 1;
+
+-- should catch error from initial INSERT
+COMMIT;