Skip to content

Commit 9a8ee1d

Browse files
committed
tableam: Add and use table_fetch_row_version().
This is essentially the tableam version of heapam_fetch(), i.e. fetching a tuple identified by a tid, performing visibility checks. Note that this different from table_index_fetch_tuple(), which is for index lookups. It therefore has to handle a tid pointing to an earlier version of a tuple if the AM uses an optimization like heap's HOT. Add comments to that end. This commit removes the stats_relation argument from heap_fetch, as it's been unused for a long time. Author: Andres Freund Reviewed-By: Haribabu Kommi Discussion: https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
1 parent c77e122 commit 9a8ee1d

File tree

9 files changed

+91
-111
lines changed

9 files changed

+91
-111
lines changed

src/backend/access/heap/heapam.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,8 +1388,7 @@ bool
13881388
heap_fetch(Relation relation,
13891389
Snapshot snapshot,
13901390
HeapTuple tuple,
1391-
Buffer *userbuf,
1392-
Relation stats_relation)
1391+
Buffer *userbuf)
13931392
{
13941393
ItemPointer tid = &(tuple->t_self);
13951394
ItemId lp;
@@ -1468,10 +1467,6 @@ heap_fetch(Relation relation,
14681467
*/
14691468
*userbuf = buffer;
14701469

1471-
/* Count the successful fetch against appropriate rel, if any */
1472-
if (stats_relation != NULL)
1473-
pgstat_count_heap_fetch(stats_relation);
1474-
14751470
return true;
14761471
}
14771472

@@ -5097,7 +5092,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
50975092
block = ItemPointerGetBlockNumber(&tupid);
50985093
ItemPointerCopy(&tupid, &(mytup.t_self));
50995094

5100-
if (!heap_fetch(rel, SnapshotAny, &mytup, &buf, NULL))
5095+
if (!heap_fetch(rel, SnapshotAny, &mytup, &buf))
51015096
{
51025097
/*
51035098
* if we fail to find the updated version of the tuple, it's

src/backend/access/heap/heapam_handler.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,30 @@ heapam_index_fetch_tuple(struct IndexFetchTableData *scan,
148148
* ------------------------------------------------------------------------
149149
*/
150150

151+
static bool
152+
heapam_fetch_row_version(Relation relation,
153+
ItemPointer tid,
154+
Snapshot snapshot,
155+
TupleTableSlot *slot)
156+
{
157+
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
158+
Buffer buffer;
159+
160+
Assert(TTS_IS_BUFFERTUPLE(slot));
161+
162+
bslot->base.tupdata.t_self = *tid;
163+
if (heap_fetch(relation, snapshot, &bslot->base.tupdata, &buffer))
164+
{
165+
/* store in slot, transferring existing pin */
166+
ExecStorePinnedBufferHeapTuple(&bslot->base.tupdata, slot, buffer);
167+
slot->tts_tableOid = RelationGetRelid(relation);
168+
169+
return true;
170+
}
171+
172+
return false;
173+
}
174+
151175
static bool
152176
heapam_tuple_satisfies_snapshot(Relation rel, TupleTableSlot *slot,
153177
Snapshot snapshot)
@@ -338,7 +362,7 @@ heapam_tuple_lock(Relation relation, ItemPointer tid, Snapshot snapshot,
338362
errmsg("tuple to be locked was already moved to another partition due to concurrent update")));
339363

340364
tuple->t_self = *tid;
341-
if (heap_fetch(relation, &SnapshotDirty, tuple, &buffer, NULL))
365+
if (heap_fetch(relation, &SnapshotDirty, tuple, &buffer))
342366
{
343367
/*
344368
* If xmin isn't what we're expecting, the slot must have
@@ -517,6 +541,7 @@ static const TableAmRoutine heapam_methods = {
517541
.tuple_update = heapam_tuple_update,
518542
.tuple_lock = heapam_tuple_lock,
519543

544+
.tuple_fetch_row_version = heapam_fetch_row_version,
520545
.tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot,
521546
};
522547

src/backend/access/table/tableamapi.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ GetTableAmRoutine(Oid amhandler)
6262
Assert(routine->index_fetch_end != NULL);
6363
Assert(routine->index_fetch_tuple != NULL);
6464

65+
Assert(routine->tuple_fetch_row_version != NULL);
6566
Assert(routine->tuple_satisfies_snapshot != NULL);
6667

6768
Assert(routine->tuple_insert != NULL);

src/backend/commands/trigger.c

Lines changed: 12 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414
#include "postgres.h"
1515

1616
#include "access/genam.h"
17-
#include "access/heapam.h"
18-
#include "access/tableam.h"
19-
#include "access/sysattr.h"
2017
#include "access/htup_details.h"
18+
#include "access/relation.h"
19+
#include "access/sysattr.h"
20+
#include "access/table.h"
21+
#include "access/tableam.h"
2122
#include "access/xact.h"
2223
#include "catalog/catalog.h"
2324
#include "catalog/dependency.h"
@@ -3379,42 +3380,12 @@ GetTupleForTrigger(EState *estate,
33793380
}
33803381
else
33813382
{
3382-
Page page;
3383-
ItemId lp;
3384-
Buffer buffer;
3385-
BufferHeapTupleTableSlot *boldslot;
3386-
HeapTuple tuple;
3387-
3388-
Assert(TTS_IS_BUFFERTUPLE(oldslot));
3389-
ExecClearTuple(oldslot);
3390-
boldslot = (BufferHeapTupleTableSlot *) oldslot;
3391-
tuple = &boldslot->base.tupdata;
3392-
3393-
buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
3394-
33953383
/*
3396-
* Although we already know this tuple is valid, we must lock the
3397-
* buffer to ensure that no one has a buffer cleanup lock; otherwise
3398-
* they might move the tuple while we try to copy it. But we can
3399-
* release the lock before actually doing the heap_copytuple call,
3400-
* since holding pin is sufficient to prevent anyone from getting a
3401-
* cleanup lock they don't already hold.
3384+
* We expect the tuple to be present, thus very simple error handling
3385+
* suffices.
34023386
*/
3403-
LockBuffer(buffer, BUFFER_LOCK_SHARE);
3404-
3405-
page = BufferGetPage(buffer);
3406-
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
3407-
3408-
Assert(ItemIdIsNormal(lp));
3409-
3410-
tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
3411-
tuple->t_len = ItemIdGetLength(lp);
3412-
tuple->t_self = *tid;
3413-
tuple->t_tableOid = RelationGetRelid(relation);
3414-
3415-
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
3416-
3417-
ExecStorePinnedBufferHeapTuple(tuple, oldslot, buffer);
3387+
if (!table_fetch_row_version(relation, tid, SnapshotAny, oldslot))
3388+
elog(ERROR, "failed to fetch tuple for trigger");
34183389
}
34193390

34203391
return true;
@@ -4193,8 +4164,6 @@ AfterTriggerExecute(EState *estate,
41934164
AfterTriggerShared evtshared = GetTriggerSharedData(event);
41944165
Oid tgoid = evtshared->ats_tgoid;
41954166
TriggerData LocTriggerData;
4196-
HeapTupleData tuple1;
4197-
HeapTupleData tuple2;
41984167
HeapTuple rettuple;
41994168
int tgindx;
42004169
bool should_free_trig = false;
@@ -4271,19 +4240,12 @@ AfterTriggerExecute(EState *estate,
42714240
default:
42724241
if (ItemPointerIsValid(&(event->ate_ctid1)))
42734242
{
4274-
Buffer buffer;
4275-
42764243
LocTriggerData.tg_trigslot = ExecGetTriggerOldSlot(estate, relInfo);
42774244

4278-
ItemPointerCopy(&(event->ate_ctid1), &(tuple1.t_self));
4279-
if (!heap_fetch(rel, SnapshotAny, &tuple1, &buffer, NULL))
4245+
if (!table_fetch_row_version(rel, &(event->ate_ctid1), SnapshotAny, LocTriggerData.tg_trigslot))
42804246
elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
4281-
ExecStorePinnedBufferHeapTuple(&tuple1,
4282-
LocTriggerData.tg_trigslot,
4283-
buffer);
42844247
LocTriggerData.tg_trigtuple =
4285-
ExecFetchSlotHeapTuple(LocTriggerData.tg_trigslot, false,
4286-
&should_free_trig);
4248+
ExecFetchSlotHeapTuple(LocTriggerData.tg_trigslot, false, &should_free_trig);
42874249
}
42884250
else
42894251
{
@@ -4295,19 +4257,12 @@ AfterTriggerExecute(EState *estate,
42954257
AFTER_TRIGGER_2CTID &&
42964258
ItemPointerIsValid(&(event->ate_ctid2)))
42974259
{
4298-
Buffer buffer;
4299-
43004260
LocTriggerData.tg_newslot = ExecGetTriggerNewSlot(estate, relInfo);
43014261

4302-
ItemPointerCopy(&(event->ate_ctid2), &(tuple2.t_self));
4303-
if (!heap_fetch(rel, SnapshotAny, &tuple2, &buffer, NULL))
4262+
if (!table_fetch_row_version(rel, &(event->ate_ctid2), SnapshotAny, LocTriggerData.tg_newslot))
43044263
elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
4305-
ExecStorePinnedBufferHeapTuple(&tuple2,
4306-
LocTriggerData.tg_newslot,
4307-
buffer);
43084264
LocTriggerData.tg_newtuple =
4309-
ExecFetchSlotHeapTuple(LocTriggerData.tg_newslot, false,
4310-
&should_free_new);
4265+
ExecFetchSlotHeapTuple(LocTriggerData.tg_newslot, false, &should_free_new);
43114266
}
43124267
else
43134268
{

src/backend/executor/execMain.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2649,17 +2649,10 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
26492649
else
26502650
{
26512651
/* ordinary table, fetch the tuple */
2652-
HeapTupleData tuple;
2653-
Buffer buffer;
2654-
2655-
tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
2656-
if (!heap_fetch(erm->relation, SnapshotAny, &tuple, &buffer,
2657-
NULL))
2652+
if (!table_fetch_row_version(erm->relation,
2653+
(ItemPointer) DatumGetPointer(datum),
2654+
SnapshotAny, slot))
26582655
elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
2659-
2660-
/* successful, store tuple */
2661-
ExecStorePinnedBufferHeapTuple(&tuple, slot, buffer);
2662-
ExecMaterializeSlot(slot);
26632656
}
26642657
}
26652658
else

src/backend/executor/nodeModifyTable.c

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -229,17 +229,13 @@ ExecCheckTIDVisible(EState *estate,
229229
TupleTableSlot *tempSlot)
230230
{
231231
Relation rel = relinfo->ri_RelationDesc;
232-
Buffer buffer;
233-
HeapTupleData tuple;
234232

235233
/* Redundantly check isolation level */
236234
if (!IsolationUsesXactSnapshot())
237235
return;
238236

239-
tuple.t_self = *tid;
240-
if (!heap_fetch(rel, SnapshotAny, &tuple, &buffer, NULL))
237+
if (!table_fetch_row_version(rel, tid, SnapshotAny, tempSlot))
241238
elog(ERROR, "failed to fetch conflicting tuple for ON CONFLICT");
242-
ExecStorePinnedBufferHeapTuple(&tuple, tempSlot, buffer);
243239
ExecCheckTupleVisible(estate, rel, tempSlot);
244240
ExecClearTuple(tempSlot);
245241
}
@@ -874,21 +870,9 @@ ldelete:;
874870
}
875871
else
876872
{
877-
BufferHeapTupleTableSlot *bslot;
878-
HeapTuple deltuple;
879-
Buffer buffer;
880-
881-
Assert(TTS_IS_BUFFERTUPLE(slot));
882-
ExecClearTuple(slot);
883-
bslot = (BufferHeapTupleTableSlot *) slot;
884-
deltuple = &bslot->base.tupdata;
885-
886-
deltuple->t_self = *tupleid;
887-
if (!heap_fetch(resultRelationDesc, SnapshotAny,
888-
deltuple, &buffer, NULL))
873+
if (!table_fetch_row_version(resultRelationDesc, tupleid,
874+
SnapshotAny, slot))
889875
elog(ERROR, "failed to fetch deleted tuple for DELETE RETURNING");
890-
891-
ExecStorePinnedBufferHeapTuple(deltuple, slot, buffer);
892876
}
893877
}
894878

src/backend/executor/nodeTidscan.c

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,6 @@ TidNext(TidScanState *node)
310310
Relation heapRelation;
311311
HeapTuple tuple;
312312
TupleTableSlot *slot;
313-
Buffer buffer = InvalidBuffer;
314313
ItemPointerData *tidList;
315314
int numTids;
316315
bool bBackward;
@@ -376,19 +375,10 @@ TidNext(TidScanState *node)
376375
if (node->tss_isCurrentOf)
377376
heap_get_latest_tid(heapRelation, snapshot, &tuple->t_self);
378377

379-
if (heap_fetch(heapRelation, snapshot, tuple, &buffer, NULL))
380-
{
381-
/*
382-
* Store the scanned tuple in the scan tuple slot of the scan
383-
* state, transferring the pin to the slot.
384-
*/
385-
ExecStorePinnedBufferHeapTuple(tuple, /* tuple to store */
386-
slot, /* slot to store in */
387-
buffer); /* buffer associated with
388-
* tuple */
389-
378+
if (table_fetch_row_version(heapRelation, &tuple->t_self, snapshot,
379+
slot))
390380
return slot;
391-
}
381+
392382
/* Bad TID or failed snapshot qual; try next */
393383
if (bBackward)
394384
node->tss_TidPtr--;

src/include/access/heapam.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ extern bool heap_getnextslot(TableScanDesc sscan,
128128
ScanDirection direction, struct TupleTableSlot *slot);
129129

130130
extern bool heap_fetch(Relation relation, Snapshot snapshot,
131-
HeapTuple tuple, Buffer *userbuf, Relation stats_relation);
131+
HeapTuple tuple, Buffer *userbuf);
132132
extern bool heap_hot_search_buffer(ItemPointer tid, Relation relation,
133133
Buffer buffer, Snapshot snapshot, HeapTuple heapTuple,
134134
bool *all_dead, bool first_call);

src/include/access/tableam.h

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,17 @@ typedef struct TableAmRoutine
271271
* ------------------------------------------------------------------------
272272
*/
273273

274+
275+
/*
276+
* Fetch tuple at `tid` into `slot, after doing a visibility test
277+
* according to `snapshot`. If a tuple was found and passed the visibility
278+
* test, returns true, false otherwise.
279+
*/
280+
bool (*tuple_fetch_row_version) (Relation rel,
281+
ItemPointer tid,
282+
Snapshot snapshot,
283+
TupleTableSlot *slot);
284+
274285
/*
275286
* Does the tuple in `slot` satisfy `snapshot`? The slot needs to be of
276287
* the appropriate type for the AM.
@@ -574,9 +585,9 @@ table_index_fetch_end(struct IndexFetchTableData *scan)
574585
}
575586

576587
/*
577-
* Fetches tuple at `tid` into `slot`, after doing a visibility test according
578-
* to `snapshot`. If a tuple was found and passed the visibility test, returns
579-
* true, false otherwise.
588+
* Fetches, as part of an index scan, tuple at `tid` into `slot`, after doing
589+
* a visibility test according to `snapshot`. If a tuple was found and passed
590+
* the visibility test, returns true, false otherwise.
580591
*
581592
* *call_again needs to be false on the first call to table_index_fetch_tuple() for
582593
* a tid. If there potentially is another tuple matching the tid, *call_again
@@ -586,6 +597,13 @@ table_index_fetch_end(struct IndexFetchTableData *scan)
586597
* *all_dead will be set to true by table_index_fetch_tuple() iff it is guaranteed
587598
* that no backend needs to see that tuple. Index AMs can use that do avoid
588599
* returning that tid in future searches.
600+
*
601+
* The difference between this function and table_fetch_row_version is that
602+
* this function returns the currently visible version of a row if the AM
603+
* supports storing multiple row versions reachable via a single index entry
604+
* (like heap's HOT). Whereas table_fetch_row_version only evaluates the the
605+
* tuple exactly at `tid`. Outside of index entry ->table tuple lookups,
606+
* table_fetch_row_version is what's usually needed.
589607
*/
590608
static inline bool
591609
table_index_fetch_tuple(struct IndexFetchTableData *scan,
@@ -606,6 +624,25 @@ table_index_fetch_tuple(struct IndexFetchTableData *scan,
606624
* ------------------------------------------------------------------------
607625
*/
608626

627+
628+
/*
629+
* Fetch tuple at `tid` into `slot, after doing a visibility test according to
630+
* `snapshot`. If a tuple was found and passed the visibility test, returns
631+
* true, false otherwise.
632+
*
633+
* See table_index_fetch_tuple's comment about what the difference between
634+
* these functions is. This function is the correct to use outside of
635+
* index entry->table tuple lookups.
636+
*/
637+
static inline bool
638+
table_fetch_row_version(Relation rel,
639+
ItemPointer tid,
640+
Snapshot snapshot,
641+
TupleTableSlot *slot)
642+
{
643+
return rel->rd_tableam->tuple_fetch_row_version(rel, tid, snapshot, slot);
644+
}
645+
609646
/*
610647
* Return true iff tuple in slot satisfies the snapshot.
611648
*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy