aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeLockRows.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeLockRows.c')
-rw-r--r--src/backend/executor/nodeLockRows.c92
1 files changed, 35 insertions, 57 deletions
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index 5a12b445a69..76f0f9d66e5 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -67,6 +67,12 @@ lnext:
epq_needed = false;
/*
+ * Initialize EPQ machinery. Need to do that early because source tuples
+ * are stored in slots initialized therein.
+ */
+ EvalPlanQualBegin(&node->lr_epqstate, estate);
+
+ /*
* Attempt to lock the source tuple(s). (Note we only have locking
* rowmarks in lr_arowMarks.)
*/
@@ -74,7 +80,6 @@ lnext:
{
ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc);
ExecRowMark *erm = aerm->rowmark;
- HeapTuple *testTuple;
Datum datum;
bool isNull;
HeapTupleData tuple;
@@ -82,13 +87,11 @@ lnext:
HeapUpdateFailureData hufd;
LockTupleMode lockmode;
HTSU_Result test;
- HeapTuple copyTuple;
+ TupleTableSlot *markSlot;
/* clear any leftover test tuple for this rel */
- testTuple = &(node->lr_curtuples[erm->rti - 1]);
- if (*testTuple != NULL)
- heap_freetuple(*testTuple);
- *testTuple = NULL;
+ markSlot = EvalPlanQualSlot(&node->lr_epqstate, erm->relation, erm->rti);
+ ExecClearTuple(markSlot);
/* if child rel, must check whether it produced this row */
if (erm->rti != erm->prti)
@@ -135,19 +138,18 @@ lnext:
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot lock rows in foreign table \"%s\"",
RelationGetRelationName(erm->relation))));
- copyTuple = fdwroutine->RefetchForeignRow(estate,
- erm,
- datum,
- &updated);
- if (copyTuple == NULL)
+
+ fdwroutine->RefetchForeignRow(estate,
+ erm,
+ datum,
+ markSlot,
+ &updated);
+ if (TupIsNull(markSlot))
{
/* couldn't get the lock, so skip this row */
goto lnext;
}
- /* save locked tuple for possible EvalPlanQual testing below */
- *testTuple = copyTuple;
-
/*
* if FDW says tuple was updated before getting locked, we need to
* perform EPQ testing to see if quals are still satisfied
@@ -230,11 +232,10 @@ lnext:
}
/* updated, so fetch and lock the updated version */
- copyTuple = EvalPlanQualFetch(estate, erm->relation,
- lockmode, erm->waitPolicy,
- &hufd.ctid, hufd.xmax);
-
- if (copyTuple == NULL)
+ if (!EvalPlanQualFetch(estate, erm->relation,
+ lockmode, erm->waitPolicy,
+ &hufd.ctid, hufd.xmax,
+ markSlot))
{
/*
* Tuple was deleted; or it's locked and we're under SKIP
@@ -243,10 +244,7 @@ lnext:
goto lnext;
}
/* remember the actually locked tuple's TID */
- tuple.t_self = copyTuple->t_self;
-
- /* Save locked tuple for EvalPlanQual testing below */
- *testTuple = copyTuple;
+ tuple.t_self = markSlot->tts_tid;
/* Remember we need to do EPQ testing */
epq_needed = true;
@@ -272,42 +270,34 @@ lnext:
*/
if (epq_needed)
{
- /* Initialize EPQ machinery */
- EvalPlanQualBegin(&node->lr_epqstate, estate);
-
/*
- * Transfer any already-fetched tuples into the EPQ state, and fetch a
- * copy of any rows that were successfully locked without any update
- * having occurred. (We do this in a separate pass so as to avoid
- * overhead in the common case where there are no concurrent updates.)
- * Make sure any inactive child rels have NULL test tuples in EPQ.
+ * Fetch a copy of any rows that were successfully locked without any
+ * update having occurred. (We do this in a separate pass so as to
+ * avoid overhead in the common case where there are no concurrent
+ * updates.) Make sure any inactive child rels have NULL test tuples
+ * in EPQ.
*/
foreach(lc, node->lr_arowMarks)
{
ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc);
ExecRowMark *erm = aerm->rowmark;
+ TupleTableSlot *markSlot;
HeapTupleData tuple;
- Buffer buffer;
+ Buffer buffer;
+
+ markSlot = EvalPlanQualSlot(&node->lr_epqstate, erm->relation, erm->rti);
/* skip non-active child tables, but clear their test tuples */
if (!erm->ermActive)
{
Assert(erm->rti != erm->prti); /* check it's child table */
- EvalPlanQualSetTuple(&node->lr_epqstate, erm->rti, NULL);
+ ExecClearTuple(markSlot);
continue;
}
/* was tuple updated and fetched above? */
- if (node->lr_curtuples[erm->rti - 1] != NULL)
- {
- /* yes, so set it as the EPQ test tuple for this rel */
- EvalPlanQualSetTuple(&node->lr_epqstate,
- erm->rti,
- node->lr_curtuples[erm->rti - 1]);
- /* freeing this tuple is now the responsibility of EPQ */
- node->lr_curtuples[erm->rti - 1] = NULL;
+ if (!TupIsNull(markSlot))
continue;
- }
/* foreign tables should have been fetched above */
Assert(erm->relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE);
@@ -318,11 +308,9 @@ lnext:
if (!heap_fetch(erm->relation, SnapshotAny, &tuple, &buffer,
false, NULL))
elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
-
- /* successful, copy and store tuple */
- EvalPlanQualSetTuple(&node->lr_epqstate, erm->rti,
- heap_copytuple(&tuple));
- ReleaseBuffer(buffer);
+ ExecStorePinnedBufferHeapTuple(&tuple, markSlot, buffer);
+ ExecMaterializeSlot(markSlot);
+ /* successful, use tuple in slot */
}
/*
@@ -402,13 +390,6 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
lrstate->ps.ps_ProjInfo = NULL;
/*
- * Create workspace in which we can remember per-RTE locked tuples
- */
- lrstate->lr_ntables = estate->es_range_table_size;
- lrstate->lr_curtuples = (HeapTuple *)
- palloc0(lrstate->lr_ntables * sizeof(HeapTuple));
-
- /*
* Locate the ExecRowMark(s) that this node is responsible for, and
* construct ExecAuxRowMarks for them. (InitPlan should already have
* built the global list of ExecRowMarks.)
@@ -425,9 +406,6 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
if (rc->isParent)
continue;
- /* safety check on size of lr_curtuples array */
- Assert(rc->rti > 0 && rc->rti <= lrstate->lr_ntables);
-
/* find ExecRowMark and build ExecAuxRowMark */
erm = ExecFindRowMark(estate, rc->rti, false);
aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist);