0001-Evade-extra-table_tuple_fetch_row_version-in-Exe-v11.patch
application/octet-stream
Filename: 0001-Evade-extra-table_tuple_fetch_row_version-in-Exe-v11.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch v11-0001
Subject: Evade extra table_tuple_fetch_row_version() in ExecUpdate()/ExecDelete()
| File | + | − |
|---|---|---|
| src/backend/executor/nodeModifyTable.c | 33 | 13 |
From cff9a17e02e98f4bdfadfd251174605588c46ea2 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Wed, 11 Jan 2023 15:00:49 +0300
Subject: [PATCH 1/2] Evade extra table_tuple_fetch_row_version() in
ExecUpdate()/ExecDelete()
We can skip table_tuple_fetch_row_version() in the case we already fetched the
tuple during locking it.
Reported-by:
Bug:
Discussion:
Author:
Reviewed-by:
Tested-by:
Backpatch-through:
---
src/backend/executor/nodeModifyTable.c | 46 ++++++++++++++++++--------
1 file changed, 33 insertions(+), 13 deletions(-)
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 687a5422eab..87a4e553b9e 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1561,6 +1561,21 @@ ldelete:
{
case TM_Ok:
Assert(context->tmfd.traversed);
+
+ /*
+ * Save locked tuple for further processing of
+ * RETURNING clause.
+ */
+ if (processReturning &&
+ resultRelInfo->ri_projectReturning &&
+ !resultRelInfo->ri_FdwRoutine)
+ {
+ TupleTableSlot *returningSlot;
+ returningSlot = ExecGetReturningSlot(estate, resultRelInfo);
+ ExecCopySlot(returningSlot, inputslot);
+ ExecMaterializeSlot(returningSlot);
+ }
+
epqslot = EvalPlanQual(context->epqstate,
resultRelationDesc,
resultRelInfo->ri_RangeTableIndex,
@@ -1675,12 +1690,16 @@ ldelete:
}
else
{
+ /*
+ * Tuple can be already fetched to the returning slot in case we've
+ * previously locked it. Fetch the tuple only if the slot is empty.
+ */
slot = ExecGetReturningSlot(estate, resultRelInfo);
if (oldtuple != NULL)
{
ExecForceStoreHeapTuple(oldtuple, slot, false);
}
- else
+ else if (TupIsNull(slot))
{
if (!table_tuple_fetch_row_version(resultRelationDesc, tupleid,
SnapshotAny, slot))
@@ -2377,6 +2396,19 @@ redo_act:
case TM_Ok:
Assert(context->tmfd.traversed);
+ /* Make sure ri_oldTupleSlot is initialized. */
+ if (unlikely(!resultRelInfo->ri_projectNewInfoValid))
+ ExecInitUpdateProjection(context->mtstate,
+ resultRelInfo);
+
+ /*
+ * Save the locked tuple for further calculation of
+ * the new tuple.
+ */
+ oldSlot = resultRelInfo->ri_oldTupleSlot;
+ ExecCopySlot(oldSlot, inputslot);
+ ExecMaterializeSlot(oldSlot);
+
epqslot = EvalPlanQual(context->epqstate,
resultRelationDesc,
resultRelInfo->ri_RangeTableIndex,
@@ -2385,18 +2417,6 @@ redo_act:
/* Tuple not passing quals anymore, exiting... */
return NULL;
- /* Make sure ri_oldTupleSlot is initialized. */
- if (unlikely(!resultRelInfo->ri_projectNewInfoValid))
- ExecInitUpdateProjection(context->mtstate,
- resultRelInfo);
-
- /* Fetch the most recent version of old tuple. */
- oldSlot = resultRelInfo->ri_oldTupleSlot;
- if (!table_tuple_fetch_row_version(resultRelationDesc,
- tupleid,
- SnapshotAny,
- oldSlot))
- elog(ERROR, "failed to fetch tuple being updated");
slot = ExecGetUpdateNewTuple(resultRelInfo,
epqslot, oldSlot);
goto redo_act;
--
2.37.1 (Apple Git-137.1)