*** a/src/backend/executor/execMain.c --- b/src/backend/executor/execMain.c *************** *** 1847,1854 **** EvalPlanQualFetch(EState *estate, Relation relation, int lockmode, switch (test) { case HeapTupleSelfUpdated: - /* treat it as deleted; do not process */ ReleaseBuffer(buffer); return NULL; case HeapTupleMayBeUpdated: --- 1847,1862 ---- switch (test) { case HeapTupleSelfUpdated: ReleaseBuffer(buffer); + if (!ItemPointerEquals(&update_ctid, &tuple.t_self)) + { + /* it was updated, so look at the updated version */ + tuple.t_self = update_ctid; + /* updated row should have xmin matching this xmax */ + priorXmax = update_xmax; + continue; + } + /* treat it as deleted; do not process */ return NULL; case HeapTupleMayBeUpdated: *** a/src/backend/executor/nodeModifyTable.c --- b/src/backend/executor/nodeModifyTable.c *************** *** 354,359 **** ldelete:; --- 354,375 ---- switch (result) { case HeapTupleSelfUpdated: + if (!ItemPointerEquals(tupleid, &update_ctid)) + { + HeapTuple copyTuple; + + estate->es_output_cid = GetCurrentCommandId(false); + copyTuple = EvalPlanQualFetch(estate, + resultRelationDesc, + LockTupleExclusive, + &update_ctid, + update_xmax); + if (copyTuple != NULL) + { + *tupleid = update_ctid = copyTuple->t_self; + goto ldelete; + } + } /* already deleted by self; nothing to do */ return NULL; *************** *** 570,575 **** lreplace:; --- 586,595 ---- switch (result) { case HeapTupleSelfUpdated: + if (!ItemPointerEquals(tupleid, &update_ctid)) + ereport(ERROR, + (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), + errmsg("row modified by same transaction during trigger execution"))); /* already deleted by self; nothing to do */ return NULL;