diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index af7b26c..f17bc6b 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -201,12 +201,19 @@ ExecCheckHeapTupleVisible(EState *estate, } /* - * ExecCheckTIDVisible -- convenience variant of ExecCheckHeapTupleVisible() + * ExecCheckTIDVisibleOrSelfInserted -- fetch tuple and check visibility + * + * Runs ExecCheckHeapTupleVisible, unless the tuple was inserted by the + * current transaction. The check for tuples inserted by the same transaction + * is redundant in the case of commands that insert a single tuple since the + * visibility check will be satisfied. In the case of commands that insert + * multiple tuples, we don't want to report a serialization failure when we + * encounter tuples inserted earlier. */ static void -ExecCheckTIDVisible(EState *estate, - ResultRelInfo *relinfo, - ItemPointer tid) +ExecCheckTIDVisibleOrSelfInserted(EState *estate, + ResultRelInfo *relinfo, + ItemPointer tid) { Relation rel = relinfo->ri_RelationDesc; Buffer buffer; @@ -219,7 +226,8 @@ ExecCheckTIDVisible(EState *estate, tuple.t_self = *tid; if (!heap_fetch(rel, SnapshotAny, &tuple, &buffer, false, NULL)) elog(ERROR, "failed to fetch conflicting tuple for ON CONFLICT"); - ExecCheckHeapTupleVisible(estate, &tuple, buffer); + if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple.t_data))) + ExecCheckHeapTupleVisible(estate, &tuple, buffer); ReleaseBuffer(buffer); } @@ -410,7 +418,8 @@ ExecInsert(ModifyTableState *mtstate, * snapshot at higher isolation levels. */ Assert(onconflict == ONCONFLICT_NOTHING); - ExecCheckTIDVisible(estate, resultRelInfo, &conflictTid); + ExecCheckTIDVisibleOrSelfInserted(estate, resultRelInfo, + &conflictTid); InstrCountFiltered2(&mtstate->ps, 1); return NULL; }