From: Andres Freund Date: Tue, 5 Feb 2019 08:58:40 +0000 (-0800) Subject: tableam: Add fetch_row_version. X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=d5a36700f52633994ea58687289a8e1bc898ca4b;p=users%2Fandresfreund%2Fpostgres.git tableam: Add fetch_row_version. Author: Reviewed-By: Discussion: https://postgr.es/m/ Backpatch: --- diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index f9b5053972..f1b6be7127 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -426,6 +426,33 @@ retry: return result; } +static bool +heapam_fetch_row_version(Relation relation, + ItemPointer tid, + Snapshot snapshot, + TupleTableSlot *slot, + Relation stats_relation) +{ + BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot; + Buffer buffer; + + Assert(TTS_IS_BUFFERTUPLE(slot)); + + if (heap_fetch(relation, tid, snapshot, &bslot->base.tupdata, &buffer, stats_relation)) + { + /* store in slot, transferring existing pin */ + ExecStorePinnedBufferHeapTuple(&bslot->base.tupdata, slot, buffer); + + slot->tts_tableOid = RelationGetRelid(relation); + + return true; + } + + slot->tts_tableOid = RelationGetRelid(relation); + + return false; +} + static bool heapam_fetch_follow(struct IndexFetchTableData *scan, ItemPointer tid, @@ -536,6 +563,7 @@ static const TableAmRoutine heapam_methods = { .tuple_update = heapam_heap_update, .tuple_lock = heapam_lock_tuple, + .tuple_fetch_row_version = heapam_fetch_row_version, .tuple_fetch_follow = heapam_fetch_follow, .tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot, }; diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 5cc15bcfef..6fbf0c2b81 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -14,10 +14,11 @@ #include "postgres.h" #include "access/genam.h" -#include "access/heapam.h" -#include "access/tableam.h" -#include "access/sysattr.h" #include "access/htup_details.h" +#include "access/relation.h" +#include "access/sysattr.h" +#include "access/table.h" +#include "access/tableam.h" #include "access/xact.h" #include "catalog/catalog.h" #include "catalog/dependency.h" @@ -3382,43 +3383,8 @@ GetTupleForTrigger(EState *estate, } else { - - Page page; - ItemId lp; - Buffer buffer; - BufferHeapTupleTableSlot *boldslot; - HeapTuple tuple; - - Assert(TTS_IS_BUFFERTUPLE(oldslot)); - ExecClearTuple(oldslot); - boldslot = (BufferHeapTupleTableSlot *) oldslot; - tuple = &boldslot->base.tupdata; - - buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid)); - - /* - * Although we already know this tuple is valid, we must lock the - * buffer to ensure that no one has a buffer cleanup lock; otherwise - * they might move the tuple while we try to copy it. But we can - * release the lock before actually doing the heap_copytuple call, - * since holding pin is sufficient to prevent anyone from getting a - * cleanup lock they don't already hold. - */ - LockBuffer(buffer, BUFFER_LOCK_SHARE); - - page = BufferGetPage(buffer); - lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid)); - - Assert(ItemIdIsNormal(lp)); - - tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp); - tuple->t_len = ItemIdGetLength(lp); - tuple->t_self = *tid; - tuple->t_tableOid = RelationGetRelid(relation); - - LockBuffer(buffer, BUFFER_LOCK_UNLOCK); - - ExecStorePinnedBufferHeapTuple(tuple, oldslot, buffer); + if (!table_fetch_row_version(relation, tid, SnapshotAny, oldslot, NULL)) + elog(ERROR, "couldn't fetch tuple"); } return true; @@ -4197,8 +4163,6 @@ AfterTriggerExecute(EState *estate, AfterTriggerShared evtshared = GetTriggerSharedData(event); Oid tgoid = evtshared->ats_tgoid; TriggerData LocTriggerData; - HeapTupleData tuple1; - HeapTupleData tuple2; HeapTuple rettuple; int tgindx; bool should_free_trig = false; @@ -4275,19 +4239,12 @@ AfterTriggerExecute(EState *estate, default: if (ItemPointerIsValid(&(event->ate_ctid1))) { - Buffer buffer; - LocTriggerData.tg_trigslot = ExecGetTriggerOldSlot(estate, relInfo); - ItemPointerCopy(&(event->ate_ctid1), &(tuple1.t_self)); - if (!heap_fetch(rel, &(tuple1.t_self), SnapshotAny, &tuple1, &buffer, NULL)) + if (!table_fetch_row_version(rel, &(event->ate_ctid1), SnapshotAny, LocTriggerData.tg_trigslot, NULL)) elog(ERROR, "failed to fetch tuple1 for AFTER trigger"); - ExecStorePinnedBufferHeapTuple(&tuple1, - LocTriggerData.tg_trigslot, - buffer); LocTriggerData.tg_trigtuple = - ExecFetchSlotHeapTuple(LocTriggerData.tg_trigslot, false, - &should_free_trig); + ExecFetchSlotHeapTuple(LocTriggerData.tg_trigslot, false, &should_free_trig); } else { @@ -4299,19 +4256,12 @@ AfterTriggerExecute(EState *estate, AFTER_TRIGGER_2CTID && ItemPointerIsValid(&(event->ate_ctid2))) { - Buffer buffer; - LocTriggerData.tg_newslot = ExecGetTriggerNewSlot(estate, relInfo); - ItemPointerCopy(&(event->ate_ctid2), &(tuple2.t_self)); - if (!heap_fetch(rel, &(tuple2.t_self), SnapshotAny, &tuple2, &buffer, NULL)) + if (!table_fetch_row_version(rel, &(event->ate_ctid2), SnapshotAny, LocTriggerData.tg_newslot, NULL)) elog(ERROR, "failed to fetch tuple2 for AFTER trigger"); - ExecStorePinnedBufferHeapTuple(&tuple2, - LocTriggerData.tg_newslot, - buffer); LocTriggerData.tg_newtuple = - ExecFetchSlotHeapTuple(LocTriggerData.tg_newslot, false, - &should_free_new); + ExecFetchSlotHeapTuple(LocTriggerData.tg_newslot, false, &should_free_new); } else { diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index d1db75af91..053ef683f7 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -2638,17 +2638,9 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate) else { /* ordinary table, fetch the tuple */ - HeapTupleData tuple; - Buffer buffer; - - tuple.t_self = *((ItemPointer) DatumGetPointer(datum)); - if (!heap_fetch(erm->relation, &tuple.t_self, SnapshotAny, - &tuple, &buffer, NULL)) + if (!table_fetch_row_version(erm->relation, (ItemPointer) DatumGetPointer(datum), + SnapshotAny, slot, NULL)) elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck"); - - /* successful, store tuple */ - ExecStorePinnedBufferHeapTuple(&tuple, slot, buffer); - ExecMaterializeSlot(slot); } } else diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index 91f46b88ed..aedc5297e3 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -21,7 +21,6 @@ #include "postgres.h" -#include "access/heapam.h" #include "access/htup_details.h" #include "access/tableam.h" #include "access/xact.h" @@ -275,8 +274,6 @@ lnext: ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc); ExecRowMark *erm = aerm->rowmark; TupleTableSlot *markSlot; - HeapTupleData tuple; - Buffer buffer; markSlot = EvalPlanQualSlot(&node->lr_epqstate, erm->relation, erm->rti); @@ -297,12 +294,9 @@ lnext: Assert(ItemPointerIsValid(&(erm->curCtid))); /* okay, fetch the tuple */ - tuple.t_self = erm->curCtid; - if (!heap_fetch(erm->relation, &tuple.t_self, SnapshotAny, &tuple, &buffer, - NULL)) + if (!table_fetch_row_version(erm->relation, &erm->curCtid, SnapshotAny, markSlot, + NULL)) elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck"); - ExecStorePinnedBufferHeapTuple(&tuple, markSlot, buffer); - ExecMaterializeSlot(markSlot); /* successful, use tuple in slot */ } diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 2dd37a84d0..f4f95428af 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -230,18 +230,15 @@ ExecCheckTIDVisible(EState *estate, TupleTableSlot *tempSlot) { Relation rel = relinfo->ri_RelationDesc; - Buffer buffer; - HeapTupleData tuple; /* Redundantly check isolation level */ if (!IsolationUsesXactSnapshot()) return; - tuple.t_self = *tid; - if (!heap_fetch(rel, &tuple.t_self, SnapshotAny, &tuple, &buffer, NULL)) + if (!table_fetch_row_version(rel, tid, SnapshotAny, tempSlot, NULL)) elog(ERROR, "failed to fetch conflicting tuple for ON CONFLICT"); - ExecStorePinnedBufferHeapTuple(&tuple, tempSlot, buffer); ExecCheckHeapTupleVisible(estate, rel, tempSlot); + ExecClearTuple(tempSlot); } /* ---------------------------------------------------------------- @@ -851,21 +848,9 @@ ldelete:; } else { - BufferHeapTupleTableSlot *bslot; - HeapTuple deltuple; - Buffer buffer; - - Assert(TTS_IS_BUFFERTUPLE(slot)); - ExecClearTuple(slot); - bslot = (BufferHeapTupleTableSlot *) slot; - deltuple = &bslot->base.tupdata; - - deltuple->t_self = *tupleid; - if (!heap_fetch(resultRelationDesc, &deltuple->t_self, SnapshotAny, - deltuple, &buffer, NULL)) + if (!table_fetch_row_version(resultRelationDesc, tupleid, SnapshotAny, + slot, NULL)) elog(ERROR, "failed to fetch deleted tuple for DELETE RETURNING"); - - ExecStorePinnedBufferHeapTuple(deltuple, slot, buffer); } } diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index b819cf2383..7d496cc410 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -310,7 +310,6 @@ TidNext(TidScanState *node) Relation heapRelation; HeapTuple tuple; TupleTableSlot *slot; - Buffer buffer = InvalidBuffer; ItemPointerData *tidList; int numTids; bool bBackward; @@ -376,19 +375,9 @@ TidNext(TidScanState *node) if (node->tss_isCurrentOf) heap_get_latest_tid(heapRelation, snapshot, &tuple->t_self); - if (heap_fetch(heapRelation, &tuple->t_self, snapshot, tuple, &buffer, NULL)) - { - /* - * Store the scanned tuple in the scan tuple slot of the scan - * state, transferring the pin to the slot. - */ - ExecStorePinnedBufferHeapTuple(tuple, /* tuple to store */ - slot, /* slot to store in */ - buffer); /* buffer associated with - * tuple */ - + if (table_fetch_row_version(heapRelation, &tuple->t_self, snapshot, slot, NULL)) return slot; - } + /* Bad TID or failed snapshot qual; try next */ if (bBackward) node->tss_TidPtr--; diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h index 22e15506ec..fa5ea9c668 100644 --- a/src/include/access/tableam.h +++ b/src/include/access/tableam.h @@ -160,6 +160,11 @@ typedef struct TableAmRoutine * ------------------------------------------------------------------------ */ + bool (*tuple_fetch_row_version) (Relation rel, + ItemPointer tid, + Snapshot snapshot, + TupleTableSlot *slot, + Relation stats_relation); bool (*tuple_fetch_follow) (struct IndexFetchTableData *scan, ItemPointer tid, Snapshot snapshot, @@ -429,6 +434,23 @@ table_lock_tuple(Relation rel, ItemPointer tid, Snapshot snapshot, * ---------------------------------------------------------------------------- */ +/* + * table_fetch_row_version - retrieve tuple with given tid + * + * XXX: This shouldn't just take a tid, but tid + additional information + */ +static inline bool +table_fetch_row_version(Relation rel, + ItemPointer tid, + Snapshot snapshot, + TupleTableSlot *slot, + Relation stats_relation) +{ + return rel->rd_tableam->tuple_fetch_row_version(rel, tid, + snapshot, slot, + stats_relation); +} + static inline bool table_fetch_follow(struct IndexFetchTableData *scan, ItemPointer tid,