diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execMain.c | 21 | ||||
-rw-r--r-- | src/backend/executor/nodeLockRows.c | 25 | ||||
-rw-r--r-- | src/backend/executor/nodeModifyTable.c | 6 |
3 files changed, 39 insertions, 13 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 9d5d829406e..23a6a612565 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -162,7 +162,8 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags) case CMD_SELECT: /* - * SELECT FOR UPDATE/SHARE and modifying CTEs need to mark tuples + * SELECT FOR [KEY] UPDATE/SHARE and modifying CTEs need to mark + * tuples */ if (queryDesc->plannedstmt->rowMarks != NIL || queryDesc->plannedstmt->hasModifyingCTE) @@ -775,7 +776,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) } /* - * Similarly, we have to lock relations selected FOR UPDATE/FOR SHARE + * Similarly, we have to lock relations selected FOR [KEY] UPDATE/SHARE * before we initialize the plan tree, else we'd be risking lock upgrades. * While we are at it, build the ExecRowMark list. */ @@ -794,7 +795,9 @@ InitPlan(QueryDesc *queryDesc, int eflags) switch (rc->markType) { case ROW_MARK_EXCLUSIVE: + case ROW_MARK_NOKEYEXCLUSIVE: case ROW_MARK_SHARE: + case ROW_MARK_KEYSHARE: relid = getrelid(rc->rti, rangeTable); relation = heap_open(relid, RowShareLock); break; @@ -1341,7 +1344,7 @@ ExecEndPlan(PlanState *planstate, EState *estate) } /* - * close any relations selected FOR UPDATE/FOR SHARE, again keeping locks + * close any relations selected FOR [KEY] UPDATE/SHARE, again keeping locks */ foreach(l, estate->es_rowMarks) { @@ -1694,6 +1697,7 @@ ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist) * epqstate - state for EvalPlanQual rechecking * relation - table containing tuple * rti - rangetable index of table containing tuple + * lockmode - requested tuple lock mode * *tid - t_ctid from the outdated tuple (ie, next updated version) * priorXmax - t_xmax from the outdated tuple * @@ -1702,10 +1706,13 @@ ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist) * * Returns a slot containing the new candidate update/delete tuple, or * NULL if we determine we shouldn't process the row. + * + * Note: properly, lockmode should be declared as enum LockTupleMode, + * but we use "int" to avoid having to include heapam.h in executor.h. */ TupleTableSlot * EvalPlanQual(EState *estate, EPQState *epqstate, - Relation relation, Index rti, + Relation relation, Index rti, int lockmode, ItemPointer tid, TransactionId priorXmax) { TupleTableSlot *slot; @@ -1716,7 +1723,7 @@ EvalPlanQual(EState *estate, EPQState *epqstate, /* * Get and lock the updated version of the row; if fail, return NULL. */ - copyTuple = EvalPlanQualFetch(estate, relation, LockTupleExclusive, + copyTuple = EvalPlanQualFetch(estate, relation, lockmode, tid, priorXmax); if (copyTuple == NULL) @@ -1864,7 +1871,7 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode, test = heap_lock_tuple(relation, &tuple, estate->es_output_cid, lockmode, false /* wait */, - &buffer, &hufd); + false, &buffer, &hufd); /* We now have two pins on the buffer, get rid of one */ ReleaseBuffer(buffer); @@ -1965,7 +1972,7 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode, /* updated, so look at the updated row */ tuple.t_self = tuple.t_data->t_ctid; /* updated row should have xmin matching this xmax */ - priorXmax = HeapTupleHeaderGetXmax(tuple.t_data); + priorXmax = HeapTupleHeaderGetUpdateXid(tuple.t_data); ReleaseBuffer(buffer); /* loop back to fetch next in chain */ } diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index 9b9d7941c8b..ae2d26b48b4 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -111,14 +111,29 @@ lnext: tuple.t_self = *((ItemPointer) DatumGetPointer(datum)); /* okay, try to lock the tuple */ - if (erm->markType == ROW_MARK_EXCLUSIVE) - lockmode = LockTupleExclusive; - else - lockmode = LockTupleShared; + switch (erm->markType) + { + case ROW_MARK_EXCLUSIVE: + lockmode = LockTupleExclusive; + break; + case ROW_MARK_NOKEYEXCLUSIVE: + lockmode = LockTupleNoKeyExclusive; + break; + case ROW_MARK_SHARE: + lockmode = LockTupleShare; + break; + case ROW_MARK_KEYSHARE: + lockmode = LockTupleKeyShare; + break; + default: + elog(ERROR, "unsupported rowmark type"); + lockmode = LockTupleNoKeyExclusive; /* keep compiler quiet */ + break; + } test = heap_lock_tuple(erm->relation, &tuple, estate->es_output_cid, - lockmode, erm->noWait, + lockmode, erm->noWait, true, &buffer, &hufd); ReleaseBuffer(buffer); switch (test) diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 40cc423c76d..cb084d03d47 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -403,6 +403,7 @@ ldelete:; epqstate, resultRelationDesc, resultRelInfo->ri_RangeTableIndex, + LockTupleExclusive, &hufd.ctid, hufd.xmax); if (!TupIsNull(epqslot)) @@ -569,6 +570,8 @@ ExecUpdate(ItemPointer tupleid, } else { + LockTupleMode lockmode; + /* * Check the constraints of the tuple * @@ -595,7 +598,7 @@ lreplace:; estate->es_output_cid, estate->es_crosscheck_snapshot, true /* wait for commit */, - &hufd); + &hufd, &lockmode); switch (result) { case HeapTupleSelfUpdated: @@ -647,6 +650,7 @@ lreplace:; epqstate, resultRelationDesc, resultRelInfo->ri_RangeTableIndex, + lockmode, &hufd.ctid, hufd.xmax); if (!TupIsNull(epqslot)) |