Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 764da77

Browse files
committed
Evade extra table_tuple_fetch_row_version() in ExecUpdate()/ExecDelete()
When we lock tuple using table_tuple_lock() then we at the same time fetch the locked tuple to the slot. In this case we can skip extra table_tuple_fetch_row_version() thank to we've already fetched the 'old' tuple and nobody can change it concurrently since it's locked. Discussion: https://postgr.es/m/CAPpHfdua-YFw3XTprfutzGp28xXLigFtzNbuFY8yPhqeq6X5kg%40mail.gmail.com Reviewed-by: Aleksander Alekseev, Pavel Borisov, Vignesh C, Mason Sharp Reviewed-by: Andres Freund, Chris Travers
1 parent c75a623 commit 764da77

File tree

1 file changed

+35
-13
lines changed

1 file changed

+35
-13
lines changed

src/backend/executor/nodeModifyTable.c

+35-13
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,22 @@ ExecDelete(ModifyTableContext *context,
15591559
{
15601560
case TM_Ok:
15611561
Assert(context->tmfd.traversed);
1562+
1563+
/*
1564+
* Save locked tuple for further processing of
1565+
* RETURNING clause.
1566+
*/
1567+
if (processReturning &&
1568+
resultRelInfo->ri_projectReturning &&
1569+
!resultRelInfo->ri_FdwRoutine)
1570+
{
1571+
TupleTableSlot *returningSlot;
1572+
1573+
returningSlot = ExecGetReturningSlot(estate, resultRelInfo);
1574+
ExecCopySlot(returningSlot, inputslot);
1575+
ExecMaterializeSlot(returningSlot);
1576+
}
1577+
15621578
epqslot = EvalPlanQual(context->epqstate,
15631579
resultRelationDesc,
15641580
resultRelInfo->ri_RangeTableIndex,
@@ -1673,12 +1689,17 @@ ExecDelete(ModifyTableContext *context,
16731689
}
16741690
else
16751691
{
1692+
/*
1693+
* Tuple can be already fetched to the returning slot in case
1694+
* we've previously locked it. Fetch the tuple only if the slot
1695+
* is empty.
1696+
*/
16761697
slot = ExecGetReturningSlot(estate, resultRelInfo);
16771698
if (oldtuple != NULL)
16781699
{
16791700
ExecForceStoreHeapTuple(oldtuple, slot, false);
16801701
}
1681-
else
1702+
else if (TupIsNull(slot))
16821703
{
16831704
if (!table_tuple_fetch_row_version(resultRelationDesc, tupleid,
16841705
SnapshotAny, slot))
@@ -2393,6 +2414,19 @@ ExecUpdate(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
23932414
case TM_Ok:
23942415
Assert(context->tmfd.traversed);
23952416

2417+
/* Make sure ri_oldTupleSlot is initialized. */
2418+
if (unlikely(!resultRelInfo->ri_projectNewInfoValid))
2419+
ExecInitUpdateProjection(context->mtstate,
2420+
resultRelInfo);
2421+
2422+
/*
2423+
* Save the locked tuple for further calculation
2424+
* of the new tuple.
2425+
*/
2426+
oldSlot = resultRelInfo->ri_oldTupleSlot;
2427+
ExecCopySlot(oldSlot, inputslot);
2428+
ExecMaterializeSlot(oldSlot);
2429+
23962430
epqslot = EvalPlanQual(context->epqstate,
23972431
resultRelationDesc,
23982432
resultRelInfo->ri_RangeTableIndex,
@@ -2401,18 +2435,6 @@ ExecUpdate(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
24012435
/* Tuple not passing quals anymore, exiting... */
24022436
return NULL;
24032437

2404-
/* Make sure ri_oldTupleSlot is initialized. */
2405-
if (unlikely(!resultRelInfo->ri_projectNewInfoValid))
2406-
ExecInitUpdateProjection(context->mtstate,
2407-
resultRelInfo);
2408-
2409-
/* Fetch the most recent version of old tuple. */
2410-
oldSlot = resultRelInfo->ri_oldTupleSlot;
2411-
if (!table_tuple_fetch_row_version(resultRelationDesc,
2412-
tupleid,
2413-
SnapshotAny,
2414-
oldSlot))
2415-
elog(ERROR, "failed to fetch tuple being updated");
24162438
slot = ExecGetUpdateNewTuple(resultRelInfo,
24172439
epqslot, oldSlot);
24182440
goto redo_act;

0 commit comments

Comments
 (0)