diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 8798992ecf944069448a9321c0b7a3c2216a61f9..c5a823857eee7a321f09a6bd9941cbd49d1fcffb 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.221 2007/11/04 21:25:55 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.222 2007/11/05 19:00:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -222,11 +222,11 @@ CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid)
 		(list_length(stmt->args) % 2) == 0 &&
 		RI_FKey_trigger_type(funcoid) != RI_TRIGGER_NONE)
 	{
-		ConvertTriggerToFK(stmt, funcoid);
-
 		/* Keep lock on target rel until end of xact */
 		heap_close(rel, NoLock);
 
+		ConvertTriggerToFK(stmt, funcoid);
+
 		return InvalidOid;
 	}
 
@@ -462,18 +462,23 @@ CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid)
  *
  * The conversion is complex because a pre-7.3 foreign key involved three
  * separate triggers, which were reported separately in dumps.  While the
- * single trigger on the referencing table can be ignored, we need info
- * from both of the triggers on the referenced table to build the constraint
- * declaration.  Our approach is to save info from the first trigger seen
- * in a list in TopMemoryContext.  When we see the second trigger we can
- * create the FK constraint and remove the list entry.  We match triggers
- * together by comparing the trigger arguments (which include constraint
- * name, table and column names, so should be good enough).
+ * single trigger on the referencing table adds no new information, we need
+ * to know the trigger functions of both of the triggers on the referenced
+ * table to build the constraint declaration.  Also, due to lack of proper
+ * dependency checking pre-7.3, it is possible that the source database had
+ * an incomplete set of triggers resulting in an only partially enforced
+ * FK constraint.  (This would happen if one of the tables had been dropped
+ * and re-created, but only if the DB had been affected by a 7.0 pg_dump bug
+ * that caused loss of tgconstrrelid information.)  We choose to translate to
+ * an FK constraint only when we've seen all three triggers of a set.  This is
+ * implemented by storing unmatched items in a list in TopMemoryContext.
+ * We match triggers together by comparing the trigger arguments (which
+ * include constraint name, table and column names, so should be good enough).
  */
 typedef struct {
 	List	   *args;			/* list of (T_String) Values or NIL */
-	Oid			funcoid;		/* OID of trigger function */
-	bool		isupd;			/* is it the UPDATE trigger? */
+	Oid			funcoids[3];	/* OIDs of trigger functions */
+	/* The three function OIDs are stored in the order update, delete, child */
 } OldTriggerInfo;
 
 static void
@@ -481,6 +486,12 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
 {
 	static List *info_list = NIL;
 
+	static const char * const funcdescr[3] = {
+		gettext_noop("Found referenced table's UPDATE trigger."),
+		gettext_noop("Found referenced table's DELETE trigger."),
+		gettext_noop("Found referencing table's trigger.")
+	};
+
 	char	   *constr_name;
 	char	   *fk_table_name;
 	char	   *pk_table_name;
@@ -488,7 +499,7 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
 	List	   *fk_attrs = NIL;
 	List	   *pk_attrs = NIL;
 	StringInfoData buf;
-	bool		isupd;
+	int			funcnum;
 	OldTriggerInfo *info = NULL;
 	ListCell   *l;
 	int			i;
@@ -548,73 +559,99 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
 	/* Identify class of trigger --- update, delete, or referencing-table */
 	switch (funcoid)
 	{
-		case F_RI_FKEY_CASCADE_DEL:
-		case F_RI_FKEY_RESTRICT_DEL:
-		case F_RI_FKEY_SETNULL_DEL:
-		case F_RI_FKEY_SETDEFAULT_DEL:
-		case F_RI_FKEY_NOACTION_DEL:
-			isupd = false;
-			break;
-
 		case F_RI_FKEY_CASCADE_UPD:
 		case F_RI_FKEY_RESTRICT_UPD:
 		case F_RI_FKEY_SETNULL_UPD:
 		case F_RI_FKEY_SETDEFAULT_UPD:
 		case F_RI_FKEY_NOACTION_UPD:
-			isupd = true;
+			funcnum = 0;
+			break;
+
+		case F_RI_FKEY_CASCADE_DEL:
+		case F_RI_FKEY_RESTRICT_DEL:
+		case F_RI_FKEY_SETNULL_DEL:
+		case F_RI_FKEY_SETDEFAULT_DEL:
+		case F_RI_FKEY_NOACTION_DEL:
+			funcnum = 1;
 			break;
 
 		default:
-			/* Ignore triggers on referencing table */
-			ereport(NOTICE,
-					(errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
-							constr_name, buf.data)));
-			return;
+			funcnum = 2;
+			break;
 	}
 
 	/* See if we have a match to this trigger */
 	foreach(l, info_list)
 	{
 		info = (OldTriggerInfo *) lfirst(l);
-		if (info->isupd != isupd && equal(info->args, stmt->args))
+		if (info->funcoids[funcnum] == InvalidOid &&
+			equal(info->args, stmt->args))
+		{
+			info->funcoids[funcnum] = funcoid;
 			break;
+		}
 	}
 
 	if (l == NULL)
 	{
-		/* First trigger of pair, so save away what we need */
+		/* First trigger of set, so create a new list entry */
 		MemoryContext oldContext;
 
 		ereport(NOTICE,
 				(errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
-						constr_name, buf.data)));
+						constr_name, buf.data),
+				 errdetail(funcdescr[funcnum])));
 		oldContext = MemoryContextSwitchTo(TopMemoryContext);
-		info = (OldTriggerInfo *) palloc(sizeof(OldTriggerInfo));
+		info = (OldTriggerInfo *) palloc0(sizeof(OldTriggerInfo));
 		info->args = copyObject(stmt->args);
-		info->funcoid = funcoid;
-		info->isupd = isupd;
+		info->funcoids[funcnum] = funcoid;
 		info_list = lappend(info_list, info);
 		MemoryContextSwitchTo(oldContext);
 	}
+	else if (info->funcoids[0] == InvalidOid ||
+			 info->funcoids[1] == InvalidOid ||
+			 info->funcoids[2] == InvalidOid)
+	{
+		/* Second trigger of set */
+		ereport(NOTICE,
+				(errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
+						constr_name, buf.data),
+				 errdetail(funcdescr[funcnum])));
+	}
 	else
 	{
-		/* OK, we have a pair, so make the FK constraint ALTER TABLE cmd */
+		/* OK, we have a set, so make the FK constraint ALTER TABLE cmd */
 		AlterTableStmt *atstmt = makeNode(AlterTableStmt);
 		AlterTableCmd *atcmd = makeNode(AlterTableCmd);
 		FkConstraint *fkcon = makeNode(FkConstraint);
-		Oid		updfunc,
-				delfunc;
 
 		ereport(NOTICE,
 				(errmsg("converting trigger group into constraint \"%s\" %s",
-						constr_name, buf.data)));
-
-		if (stmt->constrrel)
-			atstmt->relation = stmt->constrrel;
+						constr_name, buf.data),
+				 errdetail(funcdescr[funcnum])));
+		if (funcnum == 2)
+		{
+			/* This trigger is on the FK table */
+			atstmt->relation = stmt->relation;
+			if (stmt->constrrel)
+				fkcon->pktable = stmt->constrrel;
+			else
+			{
+				/* Work around ancient pg_dump bug that omitted constrrel */
+				fkcon->pktable = makeRangeVar(NULL, pk_table_name);
+			}
+		}
 		else
 		{
-			/* Work around ancient pg_dump bug that omitted constrrel */
-			atstmt->relation = makeRangeVar(NULL, fk_table_name);
+			/* This trigger is on the PK table */
+			fkcon->pktable = stmt->relation;
+			if (stmt->constrrel)
+				atstmt->relation = stmt->constrrel;
+			else
+			{
+				/* Work around ancient pg_dump bug that omitted constrrel */
+				atstmt->relation = makeRangeVar(NULL, fk_table_name);
+			}
 		}
 		atstmt->cmds = list_make1(atcmd);
 		atstmt->relkind = OBJECT_TABLE;
@@ -624,22 +661,10 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
 			fkcon->constr_name = NULL;
 		else
 			fkcon->constr_name = constr_name;
-		fkcon->pktable = stmt->relation;
 		fkcon->fk_attrs = fk_attrs;
 		fkcon->pk_attrs = pk_attrs;
 		fkcon->fk_matchtype = fk_matchtype;
-
-		if (isupd)
-		{
-			updfunc = funcoid;
-			delfunc = info->funcoid;
-		}
-		else
-		{
-			updfunc = info->funcoid;
-			delfunc = funcoid;
-		}
-		switch (updfunc)
+		switch (info->funcoids[0])
 		{
 			case F_RI_FKEY_NOACTION_UPD:
 				fkcon->fk_upd_action = FKCONSTR_ACTION_NOACTION;
@@ -660,7 +685,7 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
 				/* can't get here because of earlier checks */
 				elog(ERROR, "confused about RI update function");
 		}
-		switch (delfunc)
+		switch (info->funcoids[1])
 		{
 			case F_RI_FKEY_NOACTION_DEL:
 				fkcon->fk_del_action = FKCONSTR_ACTION_NOACTION;