diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 6873c3b4d9..0880ca51fb 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -2978,10 +2978,6 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
 		 * received in newslot.  Neither we nor our callers have any further
 		 * interest in the passed-in tuple, so it's okay to overwrite newslot
 		 * with the newer data.
-		 *
-		 * (Typically, newslot was also generated by ExecGetUpdateNewTuple, so
-		 * that epqslot_clean will be that same slot and the copy step below
-		 * is not needed.)
 		 */
 		if (epqslot_candidate != NULL)
 		{
@@ -2990,14 +2986,36 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
 			epqslot_clean = ExecGetUpdateNewTuple(relinfo, epqslot_candidate,
 												  oldslot);
 
-			if (newslot != epqslot_clean)
+			/*
+			 * Typically, the caller's newslot was also generated by
+			 * ExecGetUpdateNewTuple, so that epqslot_clean will be the same
+			 * slot and copying is not needed.  But do the right thing if it
+			 * isn't.
+			 */
+			if (unlikely(newslot != epqslot_clean))
 				ExecCopySlot(newslot, epqslot_clean);
+
+			/*
+			 * At this point newslot contains a virtual tuple that may
+			 * reference some fields of oldslot's tuple in some disk buffer.
+			 * If that tuple is in a different page than the original target
+			 * tuple, then our only pin on that buffer is oldslot's, and we're
+			 * about to release it.  Hence we'd better materialize newslot to
+			 * ensure it doesn't contain references into an unpinned buffer.
+			 * (We'd materialize it below anyway, but too late for safety.)
+			 */
+			ExecMaterializeSlot(newslot);
 		}
 
+		/*
+		 * Here we convert oldslot to a materialized slot holding trigtuple.
+		 * Neither slot passed to the triggers will hold any buffer pin.
+		 */
 		trigtuple = ExecFetchSlotHeapTuple(oldslot, true, &should_free_trig);
 	}
 	else
 	{
+		/* Put the FDW-supplied tuple into oldslot to unify the cases */
 		ExecForceStoreHeapTuple(fdw_trigtuple, oldslot, false);
 		trigtuple = fdw_trigtuple;
 	}
