diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
new file mode 100644
index c333d71..b9781eb
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2765,9 +2765,28 @@ ExecUpdate(ModifyTableContext *context,
 	 * Prepare for the update.  This includes BEFORE ROW triggers, so we're
 	 * done if it says we are.
 	 */
+	context->tmfd.traversed = false;
 	if (!ExecUpdatePrologue(context, resultRelInfo, tupleid, oldtuple, slot, NULL))
 		return NULL;
 
+	/*
+	 * If the target tuple was concurrently updated, the trigger code will
+	 * have done EPQ and updated tupleid, following the update chain.  In this
+	 * case, we must fetch the most recent version of old tuple for the
+	 * benefit of RETURNING.  Technically, we could get away with not doing
+	 * this, if there is no RETURNING clause, or it doesn't refer to OLD, but
+	 * it seems preferable to always ensure that the contents of oldSlot are
+	 * correct.
+	 */
+	if (context->tmfd.traversed)
+	{
+		if (!table_tuple_fetch_row_version(resultRelInfo->ri_RelationDesc,
+										   tupleid,
+										   SnapshotAny,
+										   oldSlot))
+			elog(ERROR, "failed to re-fetch tuple updated during trigger execution");
+	}
+
 	/* INSTEAD OF ROW UPDATE Triggers */
 	if (resultRelInfo->ri_TrigDesc &&
 		resultRelInfo->ri_TrigDesc->trig_update_instead_row)
diff --git a/src/test/isolation/expected/eval-plan-qual-trigger.out b/src/test/isolation/expected/eval-plan-qual-trigger.out
new file mode 100644
index f6714c2..eca8606
--- a/src/test/isolation/expected/eval-plan-qual-trigger.out
+++ b/src/test/isolation/expected/eval-plan-qual-trigger.out
@@ -61,11 +61,11 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
 
-key  |data              
------+------------------
-key-a|val-a-s1-ups1-ups2
+key  |data              |check_old_and_new
+-----+------------------+-----------------
+key-a|val-a-s1-ups1-ups2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -132,11 +132,11 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
 
-key  |data         
------+-------------
-key-a|val-a-s1-ups2
+key  |data         |check_old_and_new
+-----+-------------+-----------------
+key-a|val-a-s1-ups2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -205,11 +205,11 @@ step s2_del_a:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *
+    RETURNING *, data = old.data AS check_old;
 
-key  |data         
------+-------------
-key-a|val-a-s1-ups1
+key  |data         |check_old
+-----+-------------+---------
+key-a|val-a-s1-ups1|t        
 (1 row)
 
 step s2_c: COMMIT;
@@ -277,11 +277,11 @@ step s2_del_a:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *
+    RETURNING *, data = old.data AS check_old;
 
-key  |data    
------+--------
-key-a|val-a-s1
+key  |data    |check_old
+-----+--------+---------
+key-a|val-a-s1|t        
 (1 row)
 
 step s2_c: COMMIT;
@@ -343,7 +343,7 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-a = text key-a: t
@@ -352,9 +352,9 @@ s2: NOTICE:  trigger: name rep_b_u; when
 s2: NOTICE:  upd: text key-b = text key-a: f
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1-ups1) new: (key-a,val-a-s1-ups1-ups2)
 step s2_upd_a_data: <... completed>
-key  |data              
------+------------------
-key-a|val-a-s1-ups1-ups2
+key  |data              |check_old_and_new
+-----+------------------+-----------------
+key-a|val-a-s1-ups1-ups2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -417,16 +417,16 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_r: ROLLBACK;
 s2: NOTICE:  trigger: name rep_b_u; when: BEFORE; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 s2: NOTICE:  upd: text key-b = text key-a: f
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 step s2_upd_a_data: <... completed>
-key  |data         
------+-------------
-key-a|val-a-s1-ups2
+key  |data         |check_old_and_new
+-----+-------------+-----------------
+key-a|val-a-s1-ups2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -491,7 +491,7 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-a = text key-a: t
@@ -500,9 +500,9 @@ s2: NOTICE:  trigger: name rep_b_u; when
 s2: NOTICE:  upd: text key-b = text key-a: f
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1-ups1) new: (key-a,val-a-s1-ups1-ups2)
 step s2_upd_a_data: <... completed>
-key  |data              
------+------------------
-key-a|val-a-s1-ups1-ups2
+key  |data              |check_old_and_new
+-----+------------------+-----------------
+key-a|val-a-s1-ups1-ups2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -567,16 +567,16 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_r: ROLLBACK;
 s2: NOTICE:  trigger: name rep_b_u; when: BEFORE; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 s2: NOTICE:  upd: text key-b = text key-a: f
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 step s2_upd_a_data: <... completed>
-key  |data         
------+-------------
-key-a|val-a-s1-ups2
+key  |data         |check_old_and_new
+-----+-------------+-----------------
+key-a|val-a-s1-ups2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -641,13 +641,13 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-b = text key-a: f
 step s2_upd_a_data: <... completed>
-key|data
----+----
+key|data|check_old_and_new
+---+----+-----------------
 (0 rows)
 
 step s2_c: COMMIT;
@@ -711,16 +711,16 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_r: ROLLBACK;
 s2: NOTICE:  trigger: name rep_b_u; when: BEFORE; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 s2: NOTICE:  upd: text key-b = text key-a: f
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 step s2_upd_a_data: <... completed>
-key  |data         
------+-------------
-key-a|val-a-s1-ups2
+key  |data         |check_old_and_new
+-----+-------------+-----------------
+key-a|val-a-s1-ups2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -873,7 +873,7 @@ step s2_upsert_a_data:
         WHERE
             noisy_oper('upd', trigtest.key, '=', 'key-a') AND
             noisy_oper('upk', trigtest.data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-upserts2' AS check_old_and_new;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-a = text key-a: t
@@ -881,9 +881,9 @@ s2: NOTICE:  upk: text val-a-s1-ups1 <>
 s2: NOTICE:  trigger: name rep_b_u; when: BEFORE; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1-ups1) new: (key-a,val-a-s1-ups1-upserts2)
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1-ups1) new: (key-a,val-a-s1-ups1-upserts2)
 step s2_upsert_a_data: <... completed>
-key  |data                  
------+----------------------
-key-a|val-a-s1-ups1-upserts2
+key  |data                  |check_old_and_new
+-----+----------------------+-----------------
+key-a|val-a-s1-ups1-upserts2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -955,7 +955,7 @@ step s2_upsert_a_data:
         WHERE
             noisy_oper('upd', trigtest.key, '=', 'key-a') AND
             noisy_oper('upk', trigtest.data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-upserts2' AS check_old_and_new;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-a = text key-a: t
@@ -963,9 +963,9 @@ s2: NOTICE:  upk: text val-a-s1-ups1 <>
 s2: NOTICE:  trigger: name rep_b_u; when: BEFORE; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1-ups1) new: (key-a,val-a-s1-ups1-upserts2)
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1-ups1) new: (key-a,val-a-s1-ups1-upserts2)
 step s2_upsert_a_data: <... completed>
-key  |data                  
------+----------------------
-key-a|val-a-s1-ups1-upserts2
+key  |data                  |check_old_and_new
+-----+----------------------+-----------------
+key-a|val-a-s1-ups1-upserts2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -1012,7 +1012,7 @@ step s2_upsert_a_data:
         WHERE
             noisy_oper('upd', trigtest.key, '=', 'key-a') AND
             noisy_oper('upk', trigtest.data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-upserts2' AS check_old_and_new;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-a = text key-a: t
@@ -1020,9 +1020,9 @@ s2: NOTICE:  upk: text val-a-s1 <> text
 s2: NOTICE:  trigger: name rep_b_u; when: BEFORE; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-upserts2)
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-upserts2)
 step s2_upsert_a_data: <... completed>
-key  |data             
------+-----------------
-key-a|val-a-s1-upserts2
+key  |data             |check_old_and_new
+-----+-----------------+-----------------
+key-a|val-a-s1-upserts2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -1068,14 +1068,14 @@ step s2_upsert_a_data:
         WHERE
             noisy_oper('upd', trigtest.key, '=', 'key-a') AND
             noisy_oper('upk', trigtest.data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-upserts2' AS check_old_and_new;
  <waiting ...>
 step s1_r: ROLLBACK;
 s2: NOTICE:  trigger: name rep_a_i; when: AFTER; lev: ROWs; op: INSERT; old: <NULL> new: (key-a,val-a-upss2)
 step s2_upsert_a_data: <... completed>
-key  |data       
------+-----------
-key-a|val-a-upss2
+key  |data       |check_old_and_new
+-----+-----------+-----------------
+key-a|val-a-upss2|                 
 (1 row)
 
 step s2_c: COMMIT;
@@ -1137,7 +1137,7 @@ step s2_upsert_a_data:
         WHERE
             noisy_oper('upd', trigtest.key, '=', 'key-a') AND
             noisy_oper('upk', trigtest.data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-upserts2' AS check_old_and_new;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-a = text key-a: t
@@ -1145,9 +1145,9 @@ s2: NOTICE:  upk: text val-a-s1-ups1 <>
 s2: NOTICE:  trigger: name rep_b_u; when: BEFORE; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1-ups1) new: (key-a,val-a-s1-ups1-upserts2)
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1-ups1) new: (key-a,val-a-s1-ups1-upserts2)
 step s2_upsert_a_data: <... completed>
-key  |data                  
------+----------------------
-key-a|val-a-s1-ups1-upserts2
+key  |data                  |check_old_and_new
+-----+----------------------+-----------------
+key-a|val-a-s1-ups1-upserts2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -1209,14 +1209,14 @@ step s2_upsert_a_data:
         WHERE
             noisy_oper('upd', trigtest.key, '=', 'key-a') AND
             noisy_oper('upk', trigtest.data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-upserts2' AS check_old_and_new;
  <waiting ...>
 step s1_r: ROLLBACK;
 s2: NOTICE:  trigger: name rep_a_i; when: AFTER; lev: ROWs; op: INSERT; old: <NULL> new: (key-a,val-a-upss2)
 step s2_upsert_a_data: <... completed>
-key  |data       
------+-----------
-key-a|val-a-upss2
+key  |data       |check_old_and_new
+-----+-----------+-----------------
+key-a|val-a-upss2|                 
 (1 row)
 
 step s2_c: COMMIT;
@@ -1276,7 +1276,7 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-a = text key-a: t
@@ -1284,9 +1284,9 @@ s2: NOTICE:  upk: text val-a-s1-ups1 <>
 s2: NOTICE:  upd: text key-b = text key-a: f
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1-ups1) new: (key-a,val-a-s1-ups1-ups2)
 step s2_upd_a_data: <... completed>
-key  |data              
------+------------------
-key-a|val-a-s1-ups1-ups2
+key  |data              |check_old_and_new
+-----+------------------+-----------------
+key-a|val-a-s1-ups1-ups2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -1347,15 +1347,15 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_r: ROLLBACK;
 s2: NOTICE:  upd: text key-b = text key-a: f
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 step s2_upd_a_data: <... completed>
-key  |data         
------+-------------
-key-a|val-a-s1-ups2
+key  |data         |check_old_and_new
+-----+-------------+-----------------
+key-a|val-a-s1-ups2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -1417,7 +1417,7 @@ step s2_del_a:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *
+    RETURNING *, data = old.data AS check_old;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-a = text key-a: t
@@ -1425,9 +1425,9 @@ s2: NOTICE:  upk: text val-a-s1-ups1 <>
 s2: NOTICE:  upd: text key-b = text key-a: f
 s2: NOTICE:  trigger: name rep_a_d; when: AFTER; lev: ROWs; op: DELETE; old: (key-a,val-a-s1-ups1) new: <NULL>
 step s2_del_a: <... completed>
-key  |data         
------+-------------
-key-a|val-a-s1-ups1
+key  |data         |check_old
+-----+-------------+---------
+key-a|val-a-s1-ups1|t        
 (1 row)
 
 step s2_c: COMMIT;
@@ -1488,15 +1488,15 @@ step s2_del_a:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *
+    RETURNING *, data = old.data AS check_old;
  <waiting ...>
 step s1_r: ROLLBACK;
 s2: NOTICE:  upd: text key-b = text key-a: f
 s2: NOTICE:  trigger: name rep_a_d; when: AFTER; lev: ROWs; op: DELETE; old: (key-a,val-a-s1) new: <NULL>
 step s2_del_a: <... completed>
-key  |data    
------+--------
-key-a|val-a-s1
+key  |data    |check_old
+-----+--------+---------
+key-a|val-a-s1|t        
 (1 row)
 
 step s2_c: COMMIT;
@@ -1557,13 +1557,13 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-b = text key-a: f
 step s2_upd_a_data: <... completed>
-key|data
----+----
+key|data|check_old_and_new
+---+----+-----------------
 (0 rows)
 
 step s2_c: COMMIT;
@@ -1624,15 +1624,15 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_r: ROLLBACK;
 s2: NOTICE:  upd: text key-b = text key-a: f
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 step s2_upd_a_data: <... completed>
-key  |data         
------+-------------
-key-a|val-a-s1-ups2
+key  |data         |check_old_and_new
+-----+-------------+-----------------
+key-a|val-a-s1-ups2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -1693,13 +1693,13 @@ step s2_del_a:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *
+    RETURNING *, data = old.data AS check_old;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-b = text key-a: f
 step s2_del_a: <... completed>
-key|data
----+----
+key|data|check_old
+---+----+---------
 (0 rows)
 
 step s2_c: COMMIT;
@@ -1759,15 +1759,15 @@ step s2_del_a:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *
+    RETURNING *, data = old.data AS check_old;
  <waiting ...>
 step s1_r: ROLLBACK;
 s2: NOTICE:  upd: text key-b = text key-a: f
 s2: NOTICE:  trigger: name rep_a_d; when: AFTER; lev: ROWs; op: DELETE; old: (key-a,val-a-s1) new: <NULL>
 step s2_del_a: <... completed>
-key  |data    
------+--------
-key-a|val-a-s1
+key  |data    |check_old
+-----+--------+---------
+key-a|val-a-s1|t        
 (1 row)
 
 step s2_c: COMMIT;
@@ -1829,14 +1829,14 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-b = text key-a: f
 s2: NOTICE:  upd: text key-c = text key-a: f
 step s2_upd_a_data: <... completed>
-key|data
----+----
+key|data|check_old_and_new
+---+----+-----------------
 (0 rows)
 
 step s2_c: COMMIT;
@@ -1899,16 +1899,16 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_r: ROLLBACK;
 s2: NOTICE:  trigger: name rep_b_u; when: BEFORE; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 s2: NOTICE:  upd: text key-c = text key-a: f
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 step s2_upd_a_data: <... completed>
-key  |data         
------+-------------
-key-a|val-a-s1-ups2
+key  |data         |check_old_and_new
+-----+-------------+-----------------
+key-a|val-a-s1-ups2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -2038,7 +2038,7 @@ step s2_upd_all_data:
     WHERE
         noisy_oper('upd', key, '<>', 'mismatch') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-b <> text mismatch: t
@@ -2050,10 +2050,10 @@ s2: NOTICE:  trigger: name rep_b_u; when
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-b,val-a-s1-tobs1) new: (key-b,val-a-s1-tobs1-ups2)
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-c,val-c-s1) new: (key-c,val-c-s1-ups2)
 step s2_upd_all_data: <... completed>
-key  |data               
------+-------------------
-key-b|val-a-s1-tobs1-ups2
-key-c|val-c-s1-ups2      
+key  |data               |check_old_and_new
+-----+-------------------+-----------------
+key-b|val-a-s1-tobs1-ups2|t                
+key-c|val-c-s1-ups2      |t                
 (2 rows)
 
 step s2_c: COMMIT;
@@ -2118,13 +2118,13 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-c = text key-a: f
 step s2_upd_a_data: <... completed>
-key|data
----+----
+key|data|check_old_and_new
+---+----+-----------------
 (0 rows)
 
 step s2_c: COMMIT;
@@ -2188,16 +2188,16 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_r: ROLLBACK;
 s2: NOTICE:  trigger: name rep_b_u; when: BEFORE; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 s2: NOTICE:  upd: text key-c = text key-a: f
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 step s2_upd_a_data: <... completed>
-key  |data         
------+-------------
-key-a|val-a-s1-ups2
+key  |data         |check_old_and_new
+-----+-------------+-----------------
+key-a|val-a-s1-ups2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -2260,13 +2260,13 @@ step s2_del_a:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *
+    RETURNING *, data = old.data AS check_old;
  <waiting ...>
 step s1_c: COMMIT;
 s2: NOTICE:  upd: text key-c = text key-a: f
 step s2_del_a: <... completed>
-key|data
----+----
+key|data|check_old
+---+----+---------
 (0 rows)
 
 step s2_c: COMMIT;
@@ -2328,16 +2328,16 @@ step s2_del_a:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *
+    RETURNING *, data = old.data AS check_old;
  <waiting ...>
 step s1_r: ROLLBACK;
 s2: NOTICE:  trigger: name rep_b_d; when: BEFORE; lev: ROWs; op: DELETE; old: (key-a,val-a-s1) new: <NULL>
 s2: NOTICE:  upd: text key-c = text key-a: f
 s2: NOTICE:  trigger: name rep_a_d; when: AFTER; lev: ROWs; op: DELETE; old: (key-a,val-a-s1) new: <NULL>
 step s2_del_a: <... completed>
-key  |data    
------+--------
-key-a|val-a-s1
+key  |data    |check_old
+-----+--------+---------
+key-a|val-a-s1|t        
 (1 row)
 
 step s2_c: COMMIT;
@@ -2507,7 +2507,7 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_c: COMMIT;
 step s2_upd_a_data: <... completed>
@@ -2572,16 +2572,16 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_r: ROLLBACK;
 s2: NOTICE:  trigger: name rep_b_u; when: BEFORE; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 s2: NOTICE:  upd: text key-b = text key-a: f
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 step s2_upd_a_data: <... completed>
-key  |data         
------+-------------
-key-a|val-a-s1-ups2
+key  |data         |check_old_and_new
+-----+-------------+-----------------
+key-a|val-a-s1-ups2|t                
 (1 row)
 
 step s2_c: COMMIT;
@@ -2646,7 +2646,7 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_c: COMMIT;
 step s2_upd_a_data: <... completed>
@@ -2712,16 +2712,16 @@ step s2_upd_a_data:
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
  <waiting ...>
 step s1_r: ROLLBACK;
 s2: NOTICE:  trigger: name rep_b_u; when: BEFORE; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 s2: NOTICE:  upd: text key-b = text key-a: f
 s2: NOTICE:  trigger: name rep_a_u; when: AFTER; lev: ROWs; op: UPDATE; old: (key-a,val-a-s1) new: (key-a,val-a-s1-ups2)
 step s2_upd_a_data: <... completed>
-key  |data         
------+-------------
-key-a|val-a-s1-ups2
+key  |data         |check_old_and_new
+-----+-------------+-----------------
+key-a|val-a-s1-ups2|t                
 (1 row)
 
 step s2_c: COMMIT;
diff --git a/src/test/isolation/expected/merge-match-recheck.out b/src/test/isolation/expected/merge-match-recheck.out
new file mode 100644
index 4250b85..10ef2ad
--- a/src/test/isolation/expected/merge-match-recheck.out
+++ b/src/test/isolation/expected/merge-match-recheck.out
@@ -197,15 +197,23 @@ step merge_bal:
   MERGE INTO target t
   USING (SELECT 1 as key) s
   ON s.key = t.key
+  WHEN MATCHED AND balance < 0 THEN
+    DELETE
   WHEN MATCHED AND balance < 100 THEN
 	UPDATE SET balance = balance * 2, val = t.val || ' when1'
   WHEN MATCHED AND balance < 200 THEN
 	UPDATE SET balance = balance * 4, val = t.val || ' when2'
   WHEN MATCHED AND balance < 300 THEN
-	UPDATE SET balance = balance * 8, val = t.val || ' when3';
+	UPDATE SET balance = balance * 8, val = t.val || ' when3'
+  RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val;
  <waiting ...>
 step c2: COMMIT;
 step merge_bal: <... completed>
+key|old_balance|new_balance|status|val                               
+---+-----------+-----------+------+----------------------------------
+  1|         50|        100|s1    |setup updated by update_bal1 when1
+(1 row)
+
 step select1: SELECT * FROM target;
 key|balance|status|val                               
 ---+-------+------+----------------------------------
@@ -220,15 +228,23 @@ step merge_bal_pa:
   MERGE INTO target_pa t
   USING (SELECT 1 as key) s
   ON s.key = t.key
+  WHEN MATCHED AND balance < 0 THEN
+    DELETE
   WHEN MATCHED AND balance < 100 THEN
 	UPDATE SET balance = balance * 2, val = t.val || ' when1'
   WHEN MATCHED AND balance < 200 THEN
 	UPDATE SET balance = balance * 4, val = t.val || ' when2'
   WHEN MATCHED AND balance < 300 THEN
-	UPDATE SET balance = balance * 8, val = t.val || ' when3';
+	UPDATE SET balance = balance * 8, val = t.val || ' when3'
+  RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val;
  <waiting ...>
 step c2: COMMIT;
 step merge_bal_pa: <... completed>
+key|old_balance|new_balance|status|val                                  
+---+-----------+-----------+------+-------------------------------------
+  1|         50|        100|s1    |setup updated by update_bal1_pa when1
+(1 row)
+
 step select1_pa: SELECT * FROM target_pa;
 key|balance|status|val                                  
 ---+-------+------+-------------------------------------
@@ -245,22 +261,24 @@ step merge_bal_tg:
     MERGE INTO target_tg t
     USING (SELECT 1 as key) s
     ON s.key = t.key
+    WHEN MATCHED AND balance < 0 THEN
+      DELETE
     WHEN MATCHED AND balance < 100 THEN
       UPDATE SET balance = balance * 2, val = t.val || ' when1'
     WHEN MATCHED AND balance < 200 THEN
       UPDATE SET balance = balance * 4, val = t.val || ' when2'
     WHEN MATCHED AND balance < 300 THEN
       UPDATE SET balance = balance * 8, val = t.val || ' when3'
-    RETURNING t.*
+    RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val
   )
   SELECT * FROM t;
  <waiting ...>
 step c2: COMMIT;
 s1: NOTICE:  Update: (1,50,s1,"setup updated by update_bal1_tg") -> (1,100,s1,"setup updated by update_bal1_tg when1")
 step merge_bal_tg: <... completed>
-key|balance|status|val                                  
----+-------+------+-------------------------------------
-  1|    100|s1    |setup updated by update_bal1_tg when1
+key|old_balance|new_balance|status|val                                  
+---+-----------+-----------+------+-------------------------------------
+  1|         50|        100|s1    |setup updated by update_bal1_tg when1
 (1 row)
 
 step select1_tg: SELECT * FROM target_tg;
@@ -278,15 +296,23 @@ step merge_bal:
   MERGE INTO target t
   USING (SELECT 1 as key) s
   ON s.key = t.key
+  WHEN MATCHED AND balance < 0 THEN
+    DELETE
   WHEN MATCHED AND balance < 100 THEN
 	UPDATE SET balance = balance * 2, val = t.val || ' when1'
   WHEN MATCHED AND balance < 200 THEN
 	UPDATE SET balance = balance * 4, val = t.val || ' when2'
   WHEN MATCHED AND balance < 300 THEN
-	UPDATE SET balance = balance * 8, val = t.val || ' when3';
+	UPDATE SET balance = balance * 8, val = t.val || ' when3'
+  RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val;
  <waiting ...>
 step c2: COMMIT;
 step merge_bal: <... completed>
+key|old_balance|new_balance|status|val                                              
+---+-----------+-----------+------+-------------------------------------------------
+  1|         70|        140|s1    |setup updated by update1 updated by update6 when1
+(1 row)
+
 step select1: SELECT * FROM target;
 key|balance|status|val                                              
 ---+-------+------+-------------------------------------------------
@@ -302,15 +328,23 @@ step merge_bal_pa:
   MERGE INTO target_pa t
   USING (SELECT 1 as key) s
   ON s.key = t.key
+  WHEN MATCHED AND balance < 0 THEN
+    DELETE
   WHEN MATCHED AND balance < 100 THEN
 	UPDATE SET balance = balance * 2, val = t.val || ' when1'
   WHEN MATCHED AND balance < 200 THEN
 	UPDATE SET balance = balance * 4, val = t.val || ' when2'
   WHEN MATCHED AND balance < 300 THEN
-	UPDATE SET balance = balance * 8, val = t.val || ' when3';
+	UPDATE SET balance = balance * 8, val = t.val || ' when3'
+  RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val;
  <waiting ...>
 step c2: COMMIT;
 step merge_bal_pa: <... completed>
+key|old_balance|new_balance|status|val                                                    
+---+-----------+-----------+------+-------------------------------------------------------
+  1|         70|        140|s1    |setup updated by update1_pa updated by update6_pa when1
+(1 row)
+
 step select1_pa: SELECT * FROM target_pa;
 key|balance|status|val                                                    
 ---+-------+------+-------------------------------------------------------
@@ -329,22 +363,24 @@ step merge_bal_tg:
     MERGE INTO target_tg t
     USING (SELECT 1 as key) s
     ON s.key = t.key
+    WHEN MATCHED AND balance < 0 THEN
+      DELETE
     WHEN MATCHED AND balance < 100 THEN
       UPDATE SET balance = balance * 2, val = t.val || ' when1'
     WHEN MATCHED AND balance < 200 THEN
       UPDATE SET balance = balance * 4, val = t.val || ' when2'
     WHEN MATCHED AND balance < 300 THEN
       UPDATE SET balance = balance * 8, val = t.val || ' when3'
-    RETURNING t.*
+    RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val
   )
   SELECT * FROM t;
  <waiting ...>
 step c2: COMMIT;
 s1: NOTICE:  Update: (1,70,s1,"setup updated by update1_tg updated by update6_tg") -> (1,140,s1,"setup updated by update1_tg updated by update6_tg when1")
 step merge_bal_tg: <... completed>
-key|balance|status|val                                                    
----+-------+------+-------------------------------------------------------
-  1|    140|s1    |setup updated by update1_tg updated by update6_tg when1
+key|old_balance|new_balance|status|val                                                    
+---+-----------+-----------+------+-------------------------------------------------------
+  1|         70|        140|s1    |setup updated by update1_tg updated by update6_tg when1
 (1 row)
 
 step select1_tg: SELECT * FROM target_tg;
@@ -355,6 +391,105 @@ key|balance|status|val
 
 step c1: COMMIT;
 
+starting permutation: update6 update6 merge_bal c2 select1 c1
+step update6: UPDATE target t SET balance = balance - 100, val = t.val || ' updated by update6' WHERE t.key = 1;
+step update6: UPDATE target t SET balance = balance - 100, val = t.val || ' updated by update6' WHERE t.key = 1;
+step merge_bal: 
+  MERGE INTO target t
+  USING (SELECT 1 as key) s
+  ON s.key = t.key
+  WHEN MATCHED AND balance < 0 THEN
+    DELETE
+  WHEN MATCHED AND balance < 100 THEN
+	UPDATE SET balance = balance * 2, val = t.val || ' when1'
+  WHEN MATCHED AND balance < 200 THEN
+	UPDATE SET balance = balance * 4, val = t.val || ' when2'
+  WHEN MATCHED AND balance < 300 THEN
+	UPDATE SET balance = balance * 8, val = t.val || ' when3'
+  RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val;
+ <waiting ...>
+step c2: COMMIT;
+step merge_bal: <... completed>
+key|old_balance|new_balance|status|val                                        
+---+-----------+-----------+------+-------------------------------------------
+  1|        -40|           |s1    |setup updated by update6 updated by update6
+(1 row)
+
+step select1: SELECT * FROM target;
+key|balance|status|val
+---+-------+------+---
+(0 rows)
+
+step c1: COMMIT;
+
+starting permutation: update6_pa update6_pa merge_bal_pa c2 select1_pa c1
+step update6_pa: UPDATE target_pa t SET balance = balance - 100, val = t.val || ' updated by update6_pa' WHERE t.key = 1;
+step update6_pa: UPDATE target_pa t SET balance = balance - 100, val = t.val || ' updated by update6_pa' WHERE t.key = 1;
+step merge_bal_pa: 
+  MERGE INTO target_pa t
+  USING (SELECT 1 as key) s
+  ON s.key = t.key
+  WHEN MATCHED AND balance < 0 THEN
+    DELETE
+  WHEN MATCHED AND balance < 100 THEN
+	UPDATE SET balance = balance * 2, val = t.val || ' when1'
+  WHEN MATCHED AND balance < 200 THEN
+	UPDATE SET balance = balance * 4, val = t.val || ' when2'
+  WHEN MATCHED AND balance < 300 THEN
+	UPDATE SET balance = balance * 8, val = t.val || ' when3'
+  RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val;
+ <waiting ...>
+step c2: COMMIT;
+step merge_bal_pa: <... completed>
+key|old_balance|new_balance|status|val                                              
+---+-----------+-----------+------+-------------------------------------------------
+  1|        -40|           |s1    |setup updated by update6_pa updated by update6_pa
+(1 row)
+
+step select1_pa: SELECT * FROM target_pa;
+key|balance|status|val
+---+-------+------+---
+(0 rows)
+
+step c1: COMMIT;
+
+starting permutation: update6_tg update6_tg merge_bal_tg c2 select1_tg c1
+s2: NOTICE:  Update: (1,160,s1,setup) -> (1,60,s1,"setup updated by update6_tg")
+step update6_tg: UPDATE target_tg t SET balance = balance - 100, val = t.val || ' updated by update6_tg' WHERE t.key = 1;
+s2: NOTICE:  Update: (1,60,s1,"setup updated by update6_tg") -> (1,-40,s1,"setup updated by update6_tg updated by update6_tg")
+step update6_tg: UPDATE target_tg t SET balance = balance - 100, val = t.val || ' updated by update6_tg' WHERE t.key = 1;
+step merge_bal_tg: 
+  WITH t AS (
+    MERGE INTO target_tg t
+    USING (SELECT 1 as key) s
+    ON s.key = t.key
+    WHEN MATCHED AND balance < 0 THEN
+      DELETE
+    WHEN MATCHED AND balance < 100 THEN
+      UPDATE SET balance = balance * 2, val = t.val || ' when1'
+    WHEN MATCHED AND balance < 200 THEN
+      UPDATE SET balance = balance * 4, val = t.val || ' when2'
+    WHEN MATCHED AND balance < 300 THEN
+      UPDATE SET balance = balance * 8, val = t.val || ' when3'
+    RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val
+  )
+  SELECT * FROM t;
+ <waiting ...>
+step c2: COMMIT;
+s1: NOTICE:  Delete: (1,-40,s1,"setup updated by update6_tg updated by update6_tg")
+step merge_bal_tg: <... completed>
+key|old_balance|new_balance|status|val                                              
+---+-----------+-----------+------+-------------------------------------------------
+  1|        -40|           |s1    |setup updated by update6_tg updated by update6_tg
+(1 row)
+
+step select1_tg: SELECT * FROM target_tg;
+key|balance|status|val
+---+-------+------+---
+(0 rows)
+
+step c1: COMMIT;
+
 starting permutation: update7 update6 merge_bal c2 select1 c1
 step update7: UPDATE target t SET balance = 350, val = t.val || ' updated by update7' WHERE t.key = 1;
 step update6: UPDATE target t SET balance = balance - 100, val = t.val || ' updated by update6' WHERE t.key = 1;
@@ -362,15 +497,23 @@ step merge_bal:
   MERGE INTO target t
   USING (SELECT 1 as key) s
   ON s.key = t.key
+  WHEN MATCHED AND balance < 0 THEN
+    DELETE
   WHEN MATCHED AND balance < 100 THEN
 	UPDATE SET balance = balance * 2, val = t.val || ' when1'
   WHEN MATCHED AND balance < 200 THEN
 	UPDATE SET balance = balance * 4, val = t.val || ' when2'
   WHEN MATCHED AND balance < 300 THEN
-	UPDATE SET balance = balance * 8, val = t.val || ' when3';
+	UPDATE SET balance = balance * 8, val = t.val || ' when3'
+  RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val;
  <waiting ...>
 step c2: COMMIT;
 step merge_bal: <... completed>
+key|old_balance|new_balance|status|val                                              
+---+-----------+-----------+------+-------------------------------------------------
+  1|        250|       2000|s1    |setup updated by update7 updated by update6 when3
+(1 row)
+
 step select1: SELECT * FROM target;
 key|balance|status|val                                              
 ---+-------+------+-------------------------------------------------
@@ -385,12 +528,15 @@ step merge_bal_pa:
   MERGE INTO target_pa t
   USING (SELECT 1 as key) s
   ON s.key = t.key
+  WHEN MATCHED AND balance < 0 THEN
+    DELETE
   WHEN MATCHED AND balance < 100 THEN
 	UPDATE SET balance = balance * 2, val = t.val || ' when1'
   WHEN MATCHED AND balance < 200 THEN
 	UPDATE SET balance = balance * 4, val = t.val || ' when2'
   WHEN MATCHED AND balance < 300 THEN
-	UPDATE SET balance = balance * 8, val = t.val || ' when3';
+	UPDATE SET balance = balance * 8, val = t.val || ' when3'
+  RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val;
  <waiting ...>
 step c2: COMMIT;
 step merge_bal_pa: <... completed>
@@ -404,12 +550,15 @@ step merge_bal_pa:
   MERGE INTO target_pa t
   USING (SELECT 1 as key) s
   ON s.key = t.key
+  WHEN MATCHED AND balance < 0 THEN
+    DELETE
   WHEN MATCHED AND balance < 100 THEN
 	UPDATE SET balance = balance * 2, val = t.val || ' when1'
   WHEN MATCHED AND balance < 200 THEN
 	UPDATE SET balance = balance * 4, val = t.val || ' when2'
   WHEN MATCHED AND balance < 300 THEN
-	UPDATE SET balance = balance * 8, val = t.val || ' when3';
+	UPDATE SET balance = balance * 8, val = t.val || ' when3'
+  RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val;
  <waiting ...>
 step c2: COMMIT;
 step merge_bal_pa: <... completed>
diff --git a/src/test/isolation/specs/eval-plan-qual-trigger.spec b/src/test/isolation/specs/eval-plan-qual-trigger.spec
new file mode 100644
index 232b3e2..575fbe0
--- a/src/test/isolation/specs/eval-plan-qual-trigger.spec
+++ b/src/test/isolation/specs/eval-plan-qual-trigger.spec
@@ -120,14 +120,14 @@ step s2_del_a {
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *
+    RETURNING *, data = old.data AS check_old;
 }
 step s2_upd_a_data {
     UPDATE trigtest SET data = data || '-ups2'
     WHERE
         noisy_oper('upd', key, '=', 'key-a') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
 }
 step s2_upd_b_data {
     UPDATE trigtest SET data = data || '-ups2'
@@ -141,7 +141,7 @@ step s2_upd_all_data {
     WHERE
         noisy_oper('upd', key, '<>', 'mismatch') AND
         noisy_oper('upk', data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-ups2' AS check_old_and_new;
 }
 step s2_upsert_a_data {
     INSERT INTO trigtest VALUES ('key-a', 'val-a-upss2')
@@ -150,7 +150,7 @@ step s2_upsert_a_data {
         WHERE
             noisy_oper('upd', trigtest.key, '=', 'key-a') AND
             noisy_oper('upk', trigtest.data, '<>', 'mismatch')
-    RETURNING *;
+    RETURNING *, new.data = old.data || '-upserts2' AS check_old_and_new;
 }
 
 session s3
diff --git a/src/test/isolation/specs/merge-match-recheck.spec b/src/test/isolation/specs/merge-match-recheck.spec
new file mode 100644
index 6e7a776..6054fca
--- a/src/test/isolation/specs/merge-match-recheck.spec
+++ b/src/test/isolation/specs/merge-match-recheck.spec
@@ -10,7 +10,7 @@ setup
   INSERT INTO target VALUES (1, 160, 's1', 'setup');
 
   CREATE TABLE target_pa (key int, balance integer, status text, val text) PARTITION BY RANGE (balance);
-  CREATE TABLE target_pa1 PARTITION OF target_pa FOR VALUES FROM (0) TO (200);
+  CREATE TABLE target_pa1 PARTITION OF target_pa FOR VALUES FROM (-100) TO (200);
   CREATE TABLE target_pa2 PARTITION OF target_pa FOR VALUES FROM (200) TO (1000);
   INSERT INTO target_pa VALUES (1, 160, 's1', 'setup');
 
@@ -78,24 +78,30 @@ step "merge_bal"
   MERGE INTO target t
   USING (SELECT 1 as key) s
   ON s.key = t.key
+  WHEN MATCHED AND balance < 0 THEN
+    DELETE
   WHEN MATCHED AND balance < 100 THEN
 	UPDATE SET balance = balance * 2, val = t.val || ' when1'
   WHEN MATCHED AND balance < 200 THEN
 	UPDATE SET balance = balance * 4, val = t.val || ' when2'
   WHEN MATCHED AND balance < 300 THEN
-	UPDATE SET balance = balance * 8, val = t.val || ' when3';
+	UPDATE SET balance = balance * 8, val = t.val || ' when3'
+  RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val;
 }
 step "merge_bal_pa"
 {
   MERGE INTO target_pa t
   USING (SELECT 1 as key) s
   ON s.key = t.key
+  WHEN MATCHED AND balance < 0 THEN
+    DELETE
   WHEN MATCHED AND balance < 100 THEN
 	UPDATE SET balance = balance * 2, val = t.val || ' when1'
   WHEN MATCHED AND balance < 200 THEN
 	UPDATE SET balance = balance * 4, val = t.val || ' when2'
   WHEN MATCHED AND balance < 300 THEN
-	UPDATE SET balance = balance * 8, val = t.val || ' when3';
+	UPDATE SET balance = balance * 8, val = t.val || ' when3'
+  RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val;
 }
 step "merge_bal_tg"
 {
@@ -103,13 +109,15 @@ step "merge_bal_tg"
     MERGE INTO target_tg t
     USING (SELECT 1 as key) s
     ON s.key = t.key
+    WHEN MATCHED AND balance < 0 THEN
+      DELETE
     WHEN MATCHED AND balance < 100 THEN
       UPDATE SET balance = balance * 2, val = t.val || ' when1'
     WHEN MATCHED AND balance < 200 THEN
       UPDATE SET balance = balance * 4, val = t.val || ' when2'
     WHEN MATCHED AND balance < 300 THEN
       UPDATE SET balance = balance * 8, val = t.val || ' when3'
-    RETURNING t.*
+    RETURNING t.key, old.balance AS old_balance, new.balance AS new_balance, t.status, t.val
   )
   SELECT * FROM t;
 }
@@ -190,6 +198,11 @@ permutation "update1" "update6" "merge_b
 permutation "update1_pa" "update6_pa" "merge_bal_pa" "c2" "select1_pa" "c1"
 permutation "update1_tg" "update6_tg" "merge_bal_tg" "c2" "select1_tg" "c1"
 
+# merge_bal sees row concurrently updated twice and rechecks WHEN conditions, different check passes, and row is deleted
+permutation "update6" "update6" "merge_bal" "c2" "select1" "c1"
+permutation "update6_pa" "update6_pa" "merge_bal_pa" "c2" "select1_pa" "c1"
+permutation "update6_tg" "update6_tg" "merge_bal_tg" "c2" "select1_tg" "c1"
+
 # merge_bal sees row concurrently updated twice, first update would cause all checks to fail, second update causes different check to pass, so final balance = 2000
 permutation "update7" "update6" "merge_bal" "c2" "select1" "c1"
 
