From ce735ea792bdf40dddf1d38b64c48da1f37e3fdc Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Wed, 25 Mar 2026 00:22:17 -0400 Subject: [PATCH v18 01/19] Move heapam_handler.c index scan code to new file. Move the heapam index fetch callbacks (index_fetch_begin, index_fetch_reset, index_fetch_end, and index_fetch_tuple) into a dedicated file. This is a purely mechanical move with no functional changes. Upcoming work to add a slot-based table AM interface for index scans will substantially expand this code. Keeping it in heapam_handler.c would clutter a file whose primary role is to wire up the TableAmRoutine callbacks. Bitmap heap scans and sequential scans would benefit from similar separation in the future. Author: Peter Geoghegan Reviewed-By: Andres Freund Discussion: https://postgr.es/m/bmbrkiyjxoal6o5xadzv5bveoynrt3x37wqch7w3jnwumkq2yo@b4zmtnrfs4mh --- src/include/access/heapam.h | 9 ++ src/backend/access/heap/Makefile | 1 + src/backend/access/heap/heapam_handler.c | 109 ------------------ src/backend/access/heap/heapam_indexscan.c | 126 +++++++++++++++++++++ src/backend/access/heap/meson.build | 1 + 5 files changed, 137 insertions(+), 109 deletions(-) create mode 100644 src/backend/access/heap/heapam_indexscan.c diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index 9b4032030..62f15e0b1 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -432,6 +432,15 @@ extern void simple_heap_update(Relation relation, const ItemPointerData *otid, extern TransactionId heap_index_delete_tuples(Relation rel, TM_IndexDeleteOp *delstate); +/* in heap/heapam_indexscan.c */ +extern IndexFetchTableData *heapam_index_fetch_begin(Relation rel); +extern void heapam_index_fetch_reset(IndexFetchTableData *scan); +extern void heapam_index_fetch_end(IndexFetchTableData *scan); +extern bool heapam_index_fetch_tuple(struct IndexFetchTableData *scan, + ItemPointer tid, Snapshot snapshot, + TupleTableSlot *slot, bool *heap_continue, + bool *all_dead); + /* in heap/pruneheap.c */ extern void heap_page_prune_opt(Relation relation, Buffer buffer, Buffer *vmbuffer); diff --git a/src/backend/access/heap/Makefile b/src/backend/access/heap/Makefile index 394534172..1d27ccb91 100644 --- a/src/backend/access/heap/Makefile +++ b/src/backend/access/heap/Makefile @@ -15,6 +15,7 @@ include $(top_builddir)/src/Makefile.global OBJS = \ heapam.o \ heapam_handler.o \ + heapam_indexscan.o \ heapam_visibility.o \ heapam_xlog.o \ heaptoast.o \ diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index d40878928..eff276f0d 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -75,115 +75,6 @@ heapam_slot_callbacks(Relation relation) } -/* ------------------------------------------------------------------------ - * Index Scan Callbacks for heap AM - * ------------------------------------------------------------------------ - */ - -static IndexFetchTableData * -heapam_index_fetch_begin(Relation rel) -{ - IndexFetchHeapData *hscan = palloc0_object(IndexFetchHeapData); - - hscan->xs_base.rel = rel; - hscan->xs_cbuf = InvalidBuffer; - hscan->xs_vmbuffer = InvalidBuffer; - - return &hscan->xs_base; -} - -static void -heapam_index_fetch_reset(IndexFetchTableData *scan) -{ - IndexFetchHeapData *hscan = (IndexFetchHeapData *) scan; - - if (BufferIsValid(hscan->xs_cbuf)) - { - ReleaseBuffer(hscan->xs_cbuf); - hscan->xs_cbuf = InvalidBuffer; - } - - if (BufferIsValid(hscan->xs_vmbuffer)) - { - ReleaseBuffer(hscan->xs_vmbuffer); - hscan->xs_vmbuffer = InvalidBuffer; - } -} - -static void -heapam_index_fetch_end(IndexFetchTableData *scan) -{ - IndexFetchHeapData *hscan = (IndexFetchHeapData *) scan; - - heapam_index_fetch_reset(scan); - - pfree(hscan); -} - -static bool -heapam_index_fetch_tuple(struct IndexFetchTableData *scan, - ItemPointer tid, - Snapshot snapshot, - TupleTableSlot *slot, - bool *call_again, bool *all_dead) -{ - IndexFetchHeapData *hscan = (IndexFetchHeapData *) scan; - BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot; - bool got_heap_tuple; - - Assert(TTS_IS_BUFFERTUPLE(slot)); - - /* We can skip the buffer-switching logic if we're in mid-HOT chain. */ - if (!*call_again) - { - /* Switch to correct buffer if we don't have it already */ - Buffer prev_buf = hscan->xs_cbuf; - - hscan->xs_cbuf = ReleaseAndReadBuffer(hscan->xs_cbuf, - hscan->xs_base.rel, - ItemPointerGetBlockNumber(tid)); - - /* - * Prune page, but only if we weren't already on this page - */ - if (prev_buf != hscan->xs_cbuf) - heap_page_prune_opt(hscan->xs_base.rel, hscan->xs_cbuf, - &hscan->xs_vmbuffer); - } - - /* Obtain share-lock on the buffer so we can examine visibility */ - LockBuffer(hscan->xs_cbuf, BUFFER_LOCK_SHARE); - got_heap_tuple = heap_hot_search_buffer(tid, - hscan->xs_base.rel, - hscan->xs_cbuf, - snapshot, - &bslot->base.tupdata, - all_dead, - !*call_again); - bslot->base.tupdata.t_self = *tid; - LockBuffer(hscan->xs_cbuf, BUFFER_LOCK_UNLOCK); - - if (got_heap_tuple) - { - /* - * Only in a non-MVCC snapshot can more than one member of the HOT - * chain be visible. - */ - *call_again = !IsMVCCLikeSnapshot(snapshot); - - slot->tts_tableOid = RelationGetRelid(scan->rel); - ExecStoreBufferHeapTuple(&bslot->base.tupdata, slot, hscan->xs_cbuf); - } - else - { - /* We've reached the end of the HOT chain. */ - *call_again = false; - } - - return got_heap_tuple; -} - - /* ------------------------------------------------------------------------ * Callbacks for non-modifying operations on individual tuples for heap AM * ------------------------------------------------------------------------ diff --git a/src/backend/access/heap/heapam_indexscan.c b/src/backend/access/heap/heapam_indexscan.c new file mode 100644 index 000000000..4e8230834 --- /dev/null +++ b/src/backend/access/heap/heapam_indexscan.c @@ -0,0 +1,126 @@ +/*------------------------------------------------------------------------- + * + * heapam_indexscan.c + * heap table plain index scan and index-only scan code + * + * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/access/heap/heapam_indexscan.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/heapam.h" + + +/* ------------------------------------------------------------------------ + * Index Scan Callbacks for heap AM + * ------------------------------------------------------------------------ + */ + +IndexFetchTableData * +heapam_index_fetch_begin(Relation rel) +{ + IndexFetchHeapData *hscan = palloc0_object(IndexFetchHeapData); + + hscan->xs_base.rel = rel; + hscan->xs_cbuf = InvalidBuffer; + hscan->xs_vmbuffer = InvalidBuffer; + + return &hscan->xs_base; +} + +void +heapam_index_fetch_reset(IndexFetchTableData *scan) +{ + IndexFetchHeapData *hscan = (IndexFetchHeapData *) scan; + + if (BufferIsValid(hscan->xs_cbuf)) + { + ReleaseBuffer(hscan->xs_cbuf); + hscan->xs_cbuf = InvalidBuffer; + } + + if (BufferIsValid(hscan->xs_vmbuffer)) + { + ReleaseBuffer(hscan->xs_vmbuffer); + hscan->xs_vmbuffer = InvalidBuffer; + } +} + +void +heapam_index_fetch_end(IndexFetchTableData *scan) +{ + IndexFetchHeapData *hscan = (IndexFetchHeapData *) scan; + + heapam_index_fetch_reset(scan); + + pfree(hscan); +} + +bool +heapam_index_fetch_tuple(struct IndexFetchTableData *scan, + ItemPointer tid, + Snapshot snapshot, + TupleTableSlot *slot, + bool *heap_continue, bool *all_dead) +{ + IndexFetchHeapData *hscan = (IndexFetchHeapData *) scan; + BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot; + bool got_heap_tuple; + + Assert(TTS_IS_BUFFERTUPLE(slot)); + + /* We can skip the buffer-switching logic if we're in mid-HOT chain. */ + if (!*heap_continue) + { + /* Switch to correct buffer if we don't have it already */ + Buffer prev_buf = hscan->xs_cbuf; + + hscan->xs_cbuf = ReleaseAndReadBuffer(hscan->xs_cbuf, + hscan->xs_base.rel, + ItemPointerGetBlockNumber(tid)); + + /* + * Prune page, but only if we weren't already on this page + */ + if (prev_buf != hscan->xs_cbuf) + heap_page_prune_opt(hscan->xs_base.rel, hscan->xs_cbuf, + &hscan->xs_vmbuffer); + } + + /* Obtain share-lock on the buffer so we can examine visibility */ + LockBuffer(hscan->xs_cbuf, BUFFER_LOCK_SHARE); + got_heap_tuple = heap_hot_search_buffer(tid, + hscan->xs_base.rel, + hscan->xs_cbuf, + snapshot, + &bslot->base.tupdata, + all_dead, + !*heap_continue); + bslot->base.tupdata.t_self = *tid; + LockBuffer(hscan->xs_cbuf, BUFFER_LOCK_UNLOCK); + + if (got_heap_tuple) + { + /* + * Only in a non-MVCC snapshot can more than one member of the HOT + * chain be visible. + */ + *heap_continue = !IsMVCCLikeSnapshot(snapshot); + + slot->tts_tableOid = RelationGetRelid(scan->rel); + ExecStoreBufferHeapTuple(&bslot->base.tupdata, slot, hscan->xs_cbuf); + } + else + { + /* We've reached the end of the HOT chain. */ + *heap_continue = false; + } + + return got_heap_tuple; +} diff --git a/src/backend/access/heap/meson.build b/src/backend/access/heap/meson.build index 92ab8be3d..00ec07d7f 100644 --- a/src/backend/access/heap/meson.build +++ b/src/backend/access/heap/meson.build @@ -3,6 +3,7 @@ backend_sources += files( 'heapam.c', 'heapam_handler.c', + 'heapam_indexscan.c', 'heapam_visibility.c', 'heapam_xlog.c', 'heaptoast.c', -- 2.53.0