Thread

  1. [PATCH 2/7] Pass the number of ScanKeys to scan_rescan()

    Julien Tachoires <julien@tachoires.me> — 2025-12-02T09:40:55Z

    The number of ScanKeys passed to the table AM API routine scan_rescan()
    was not specified, forcing the table AM to keep in memory the initial
    number of ScanKeys passed via scan_begin(). Currenlty, there isn't any
    real use of the ScanKeys during a table scan, so, this is not an issue,
    but it could become a blocking point in the future if we want to
    implement quals push down - as ScanKeys - to the table AM. Due to
    runtime keys evaluation, this number of ScanKeys can vary between the
    initial call to scan_begin() and a potential further call
    to scan_rescan().
    
    table_rescan() is modified in order to reflect the changes on
    scan_rescan().
    
    table_beginscan_parallel() signature is slightly modified in order to
    pass eventual ScanKeys and their numbers to scan_begin().
    
    We also rename the variable "key" to "keys" in multiple places in
    order to make clear that this is an array of ScanKeys.
    ---
     src/backend/access/brin/brin.c            |  3 +-
     src/backend/access/gin/gininsert.c        |  3 +-
     src/backend/access/heap/heapam.c          | 22 +++++++-----
     src/backend/access/nbtree/nbtsort.c       |  3 +-
     src/backend/access/table/tableam.c        |  9 ++---
     src/backend/executor/execReplication.c    |  4 +--
     src/backend/executor/nodeBitmapHeapscan.c |  2 +-
     src/backend/executor/nodeSamplescan.c     |  2 +-
     src/backend/executor/nodeSeqscan.c        |  5 +--
     src/backend/executor/nodeTidscan.c        |  2 +-
     src/include/access/heapam.h               |  7 ++--
     src/include/access/tableam.h              | 41 ++++++++++++-----------
     12 files changed, 59 insertions(+), 44 deletions(-)
    
    diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
    index cb3331921cb..0a43f67f919 100644
    --- a/src/backend/access/brin/brin.c
    +++ b/src/backend/access/brin/brin.c
    @@ -2842,7 +2842,8 @@ _brin_parallel_scan_and_build(BrinBuildState *state,
     	indexInfo->ii_Concurrent = brinshared->isconcurrent;
     
     	scan = table_beginscan_parallel(heap,
    -									ParallelTableScanFromBrinShared(brinshared));
    +									ParallelTableScanFromBrinShared(brinshared),
    +									0, NULL);
     
     	reltuples = table_index_build_scan(heap, index, indexInfo, true, true,
     									   brinbuildCallbackParallel, state, scan);
    diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
    index f87c60a230c..9f7a55f3647 100644
    --- a/src/backend/access/gin/gininsert.c
    +++ b/src/backend/access/gin/gininsert.c
    @@ -2058,7 +2058,8 @@ _gin_parallel_scan_and_build(GinBuildState *state,
     	indexInfo->ii_Concurrent = ginshared->isconcurrent;
     
     	scan = table_beginscan_parallel(heap,
    -									ParallelTableScanFromGinBuildShared(ginshared));
    +									ParallelTableScanFromGinBuildShared(ginshared),
    +									0, NULL);
     
     	reltuples = table_index_build_scan(heap, index, indexInfo, true, progress,
     									   ginBuildCallbackParallel, state, scan);
    diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
    index 1d9f9efa4fd..25bc941a815 100644
    --- a/src/backend/access/heap/heapam.c
    +++ b/src/backend/access/heap/heapam.c
    @@ -346,10 +346,13 @@ bitmapheap_stream_read_next(ReadStream *pgsr, void *private_data,
     
     /* ----------------
      *		initscan - scan code common to heap_beginscan and heap_rescan
    + *
    + * Note: in order to pass on the ScanKeys to the scan, this function takes as
    + * arguments the number of ScanKeys and one array of ScanKeys.
      * ----------------
      */
     static void
    -initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
    +initscan(HeapScanDesc scan, int nkeys, ScanKey keys, bool keep_startblock)
     {
     	ParallelBlockTableScanDesc bpscan = NULL;
     	bool		allow_strat;
    @@ -471,10 +474,13 @@ initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
     	/* page-at-a-time fields are always invalid when not rs_inited */
     
     	/*
    -	 * copy the scan key, if appropriate
    +	 * copy the scan keys, if appropriate
     	 */
    -	if (key != NULL && scan->rs_base.rs_nkeys > 0)
    -		memcpy(scan->rs_base.rs_key, key, scan->rs_base.rs_nkeys * sizeof(ScanKeyData));
    +	if (keys != NULL && nkeys > 0)
    +	{
    +		scan->rs_base.rs_nkeys = nkeys;
    +		memcpy(scan->rs_base.rs_key, keys, nkeys * sizeof(ScanKeyData));
    +	}
     
     	/*
     	 * Currently, we only have a stats counter for sequential heap scans (but
    @@ -1127,7 +1133,7 @@ continue_page:
     
     TableScanDesc
     heap_beginscan(Relation relation, Snapshot snapshot,
    -			   int nkeys, ScanKey key,
    +			   int nkeys, ScanKey keys,
     			   ParallelTableScanDesc parallel_scan,
     			   uint32 flags)
     {
    @@ -1228,7 +1234,7 @@ heap_beginscan(Relation relation, Snapshot snapshot,
     	else
     		scan->rs_base.rs_key = NULL;
     
    -	initscan(scan, key, false);
    +	initscan(scan, nkeys, keys, false);
     
     	scan->rs_read_stream = NULL;
     
    @@ -1280,7 +1286,7 @@ heap_beginscan(Relation relation, Snapshot snapshot,
     }
     
     void
    -heap_rescan(TableScanDesc sscan, ScanKey key, bool set_params,
    +heap_rescan(TableScanDesc sscan, int nkeys, ScanKey keys, bool set_params,
     			bool allow_strat, bool allow_sync, bool allow_pagemode)
     {
     	HeapScanDesc scan = (HeapScanDesc) sscan;
    @@ -1329,7 +1335,7 @@ heap_rescan(TableScanDesc sscan, ScanKey key, bool set_params,
     	/*
     	 * reinitialize scan descriptor
     	 */
    -	initscan(scan, key, true);
    +	initscan(scan, nkeys, keys, true);
     }
     
     void
    diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c
    index 454adaee7dc..9c757a1ee95 100644
    --- a/src/backend/access/nbtree/nbtsort.c
    +++ b/src/backend/access/nbtree/nbtsort.c
    @@ -1925,7 +1925,8 @@ _bt_parallel_scan_and_sort(BTSpool *btspool, BTSpool *btspool2,
     	indexInfo = BuildIndexInfo(btspool->index);
     	indexInfo->ii_Concurrent = btshared->isconcurrent;
     	scan = table_beginscan_parallel(btspool->heap,
    -									ParallelTableScanFromBTShared(btshared));
    +									ParallelTableScanFromBTShared(btshared),
    +									0, NULL);
     	reltuples = table_index_build_scan(btspool->heap, btspool->index, indexInfo,
     									   true, progress, _bt_build_callback,
     									   &buildstate, scan);
    diff --git a/src/backend/access/table/tableam.c b/src/backend/access/table/tableam.c
    index 1e099febdc8..0efa564f7b2 100644
    --- a/src/backend/access/table/tableam.c
    +++ b/src/backend/access/table/tableam.c
    @@ -110,14 +110,14 @@ table_slot_create(Relation relation, List **reglist)
      */
     
     TableScanDesc
    -table_beginscan_catalog(Relation relation, int nkeys, ScanKeyData *key)
    +table_beginscan_catalog(Relation relation, int nkeys, ScanKeyData *keys)
     {
     	uint32		flags = SO_TYPE_SEQSCAN |
     		SO_ALLOW_STRAT | SO_ALLOW_SYNC | SO_ALLOW_PAGEMODE | SO_TEMP_SNAPSHOT;
     	Oid			relid = RelationGetRelid(relation);
     	Snapshot	snapshot = RegisterSnapshot(GetCatalogSnapshot(relid));
     
    -	return relation->rd_tableam->scan_begin(relation, snapshot, nkeys, key,
    +	return relation->rd_tableam->scan_begin(relation, snapshot, nkeys, keys,
     											NULL, flags);
     }
     
    @@ -163,7 +163,8 @@ table_parallelscan_initialize(Relation rel, ParallelTableScanDesc pscan,
     }
     
     TableScanDesc
    -table_beginscan_parallel(Relation relation, ParallelTableScanDesc pscan)
    +table_beginscan_parallel(Relation relation, ParallelTableScanDesc pscan,
    +						 int nkeys, ScanKeyData *keys)
     {
     	Snapshot	snapshot;
     	uint32		flags = SO_TYPE_SEQSCAN |
    @@ -184,7 +185,7 @@ table_beginscan_parallel(Relation relation, ParallelTableScanDesc pscan)
     		snapshot = SnapshotAny;
     	}
     
    -	return relation->rd_tableam->scan_begin(relation, snapshot, 0, NULL,
    +	return relation->rd_tableam->scan_begin(relation, snapshot, nkeys, keys,
     											pscan, flags);
     }
     
    diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c
    index def32774c90..b7d45daa55a 100644
    --- a/src/backend/executor/execReplication.c
    +++ b/src/backend/executor/execReplication.c
    @@ -388,7 +388,7 @@ RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode,
     retry:
     	found = false;
     
    -	table_rescan(scan, NULL);
    +	table_rescan(scan, 0, NULL);
     
     	/* Try to find the tuple */
     	while (table_scan_getnextslot(scan, ForwardScanDirection, scanslot))
    @@ -604,7 +604,7 @@ RelationFindDeletedTupleInfoSeq(Relation rel, TupleTableSlot *searchslot,
     	scan = table_beginscan(rel, SnapshotAny, 0, NULL);
     	scanslot = table_slot_create(rel, NULL);
     
    -	table_rescan(scan, NULL);
    +	table_rescan(scan, 0, NULL);
     
     	/* Try to find the tuple */
     	while (table_scan_getnextslot(scan, ForwardScanDirection, scanslot))
    diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
    index bf24f3d7fe0..fb778e0ae3b 100644
    --- a/src/backend/executor/nodeBitmapHeapscan.c
    +++ b/src/backend/executor/nodeBitmapHeapscan.c
    @@ -239,7 +239,7 @@ ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
     			tbm_end_iterate(&scan->st.rs_tbmiterator);
     
     		/* rescan to release any page pin */
    -		table_rescan(node->ss.ss_currentScanDesc, NULL);
    +		table_rescan(node->ss.ss_currentScanDesc, 0, NULL);
     	}
     
     	/* release bitmaps and buffers if any */
    diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
    index 6b3db7548ed..a7e172d83a4 100644
    --- a/src/backend/executor/nodeSamplescan.c
    +++ b/src/backend/executor/nodeSamplescan.c
    @@ -301,7 +301,7 @@ tablesample_init(SampleScanState *scanstate)
     	}
     	else
     	{
    -		table_rescan_set_params(scanstate->ss.ss_currentScanDesc, NULL,
    +		table_rescan_set_params(scanstate->ss.ss_currentScanDesc, 0, NULL,
     								scanstate->use_bulkread,
     								allow_sync,
     								scanstate->use_pagemode);
    diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
    index 94047d29430..454d4ee0499 100644
    --- a/src/backend/executor/nodeSeqscan.c
    +++ b/src/backend/executor/nodeSeqscan.c
    @@ -326,6 +326,7 @@ ExecReScanSeqScan(SeqScanState *node)
     
     	if (scan != NULL)
     		table_rescan(scan,		/* scan desc */
    +					 0,			/* number of new scan keys */
     					 NULL);		/* new scan keys */
     
     	ExecScanReScan((ScanState *) node);
    @@ -374,7 +375,7 @@ ExecSeqScanInitializeDSM(SeqScanState *node,
     								  estate->es_snapshot);
     	shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
     	node->ss.ss_currentScanDesc =
    -		table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
    +		table_beginscan_parallel(node->ss.ss_currentRelation, pscan, 0, NULL);
     }
     
     /* ----------------------------------------------------------------
    @@ -407,5 +408,5 @@ ExecSeqScanInitializeWorker(SeqScanState *node,
     
     	pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
     	node->ss.ss_currentScanDesc =
    -		table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
    +		table_beginscan_parallel(node->ss.ss_currentRelation, pscan, 0, NULL);
     }
    diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
    index d50c6600358..0ab70d891c4 100644
    --- a/src/backend/executor/nodeTidscan.c
    +++ b/src/backend/executor/nodeTidscan.c
    @@ -465,7 +465,7 @@ ExecReScanTidScan(TidScanState *node)
     
     	/* not really necessary, but seems good form */
     	if (node->ss.ss_currentScanDesc)
    -		table_rescan(node->ss.ss_currentScanDesc, NULL);
    +		table_rescan(node->ss.ss_currentScanDesc, 0, NULL);
     
     	ExecScanReScan(&node->ss);
     }
    diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
    index 632c4332a8c..7dd5e0bcd78 100644
    --- a/src/include/access/heapam.h
    +++ b/src/include/access/heapam.h
    @@ -325,14 +325,15 @@ typedef struct PruneFreezeResult
     
     
     extern TableScanDesc heap_beginscan(Relation relation, Snapshot snapshot,
    -									int nkeys, ScanKey key,
    +									int nkeys, ScanKey keys,
     									ParallelTableScanDesc parallel_scan,
     									uint32 flags);
     extern void heap_setscanlimits(TableScanDesc sscan, BlockNumber startBlk,
     							   BlockNumber numBlks);
     extern void heap_prepare_pagescan(TableScanDesc sscan);
    -extern void heap_rescan(TableScanDesc sscan, ScanKey key, bool set_params,
    -						bool allow_strat, bool allow_sync, bool allow_pagemode);
    +extern void heap_rescan(TableScanDesc sscan, int nkeys, ScanKey keys,
    +						bool set_params, bool allow_strat, bool allow_sync,
    +						bool allow_pagemode);
     extern void heap_endscan(TableScanDesc sscan);
     extern HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction);
     extern bool heap_getnextslot(TableScanDesc sscan,
    diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
    index 2fa790b6bf5..848aa114de1 100644
    --- a/src/include/access/tableam.h
    +++ b/src/include/access/tableam.h
    @@ -326,7 +326,7 @@ typedef struct TableAmRoutine
     	 */
     	TableScanDesc (*scan_begin) (Relation rel,
     								 Snapshot snapshot,
    -								 int nkeys, ScanKeyData *key,
    +								 int nkeys, ScanKeyData *keys,
     								 ParallelTableScanDesc pscan,
     								 uint32 flags);
     
    @@ -340,9 +340,10 @@ typedef struct TableAmRoutine
     	 * Restart relation scan.  If set_params is set to true, allow_{strat,
     	 * sync, pagemode} (see scan_begin) changes should be taken into account.
     	 */
    -	void		(*scan_rescan) (TableScanDesc scan, ScanKeyData *key,
    -								bool set_params, bool allow_strat,
    -								bool allow_sync, bool allow_pagemode);
    +	void		(*scan_rescan) (TableScanDesc scan, int nkeys,
    +								ScanKeyData *keys, bool set_params,
    +								bool allow_strat, bool allow_sync,
    +								bool allow_pagemode);
     
     	/*
     	 * Return next tuple from `scan`, store in slot.
    @@ -874,12 +875,12 @@ extern TupleTableSlot *table_slot_create(Relation relation, List **reglist);
      */
     static inline TableScanDesc
     table_beginscan(Relation rel, Snapshot snapshot,
    -				int nkeys, ScanKeyData *key)
    +				int nkeys, ScanKeyData *keys)
     {
     	uint32		flags = SO_TYPE_SEQSCAN |
     		SO_ALLOW_STRAT | SO_ALLOW_SYNC | SO_ALLOW_PAGEMODE;
     
    -	return rel->rd_tableam->scan_begin(rel, snapshot, nkeys, key, NULL, flags);
    +	return rel->rd_tableam->scan_begin(rel, snapshot, nkeys, keys, NULL, flags);
     }
     
     /*
    @@ -887,7 +888,7 @@ table_beginscan(Relation rel, Snapshot snapshot,
      * snapshot appropriate for scanning catalog relations.
      */
     extern TableScanDesc table_beginscan_catalog(Relation relation, int nkeys,
    -											 ScanKeyData *key);
    +											 ScanKeyData *keys);
     
     /*
      * Like table_beginscan(), but table_beginscan_strat() offers an extended API
    @@ -898,7 +899,7 @@ extern TableScanDesc table_beginscan_catalog(Relation relation, int nkeys,
      */
     static inline TableScanDesc
     table_beginscan_strat(Relation rel, Snapshot snapshot,
    -					  int nkeys, ScanKeyData *key,
    +					  int nkeys, ScanKeyData *keys,
     					  bool allow_strat, bool allow_sync)
     {
     	uint32		flags = SO_TYPE_SEQSCAN | SO_ALLOW_PAGEMODE;
    @@ -908,7 +909,7 @@ table_beginscan_strat(Relation rel, Snapshot snapshot,
     	if (allow_sync)
     		flags |= SO_ALLOW_SYNC;
     
    -	return rel->rd_tableam->scan_begin(rel, snapshot, nkeys, key, NULL, flags);
    +	return rel->rd_tableam->scan_begin(rel, snapshot, nkeys, keys, NULL, flags);
     }
     
     /*
    @@ -919,11 +920,11 @@ table_beginscan_strat(Relation rel, Snapshot snapshot,
      */
     static inline TableScanDesc
     table_beginscan_bm(Relation rel, Snapshot snapshot,
    -				   int nkeys, ScanKeyData *key)
    +				   int nkeys, ScanKeyData *keys)
     {
     	uint32		flags = SO_TYPE_BITMAPSCAN | SO_ALLOW_PAGEMODE;
     
    -	return rel->rd_tableam->scan_begin(rel, snapshot, nkeys, key,
    +	return rel->rd_tableam->scan_begin(rel, snapshot, nkeys, keys,
     									   NULL, flags);
     }
     
    @@ -936,7 +937,7 @@ table_beginscan_bm(Relation rel, Snapshot snapshot,
      */
     static inline TableScanDesc
     table_beginscan_sampling(Relation rel, Snapshot snapshot,
    -						 int nkeys, ScanKeyData *key,
    +						 int nkeys, ScanKeyData *keys,
     						 bool allow_strat, bool allow_sync,
     						 bool allow_pagemode)
     {
    @@ -949,7 +950,7 @@ table_beginscan_sampling(Relation rel, Snapshot snapshot,
     	if (allow_pagemode)
     		flags |= SO_ALLOW_PAGEMODE;
     
    -	return rel->rd_tableam->scan_begin(rel, snapshot, nkeys, key, NULL, flags);
    +	return rel->rd_tableam->scan_begin(rel, snapshot, nkeys, keys, NULL, flags);
     }
     
     /*
    @@ -991,9 +992,9 @@ table_endscan(TableScanDesc scan)
      * Restart a relation scan.
      */
     static inline void
    -table_rescan(TableScanDesc scan, ScanKeyData *key)
    +table_rescan(TableScanDesc scan, int nkeys, ScanKeyData *keys)
     {
    -	scan->rs_rd->rd_tableam->scan_rescan(scan, key, false, false, false, false);
    +	scan->rs_rd->rd_tableam->scan_rescan(scan, nkeys, keys, false, false, false, false);
     }
     
     /*
    @@ -1005,10 +1006,10 @@ table_rescan(TableScanDesc scan, ScanKeyData *key)
      * previously selected startblock will be kept.
      */
     static inline void
    -table_rescan_set_params(TableScanDesc scan, ScanKeyData *key,
    +table_rescan_set_params(TableScanDesc scan, int nkeys, ScanKeyData *keys,
     						bool allow_strat, bool allow_sync, bool allow_pagemode)
     {
    -	scan->rs_rd->rd_tableam->scan_rescan(scan, key, true,
    +	scan->rs_rd->rd_tableam->scan_rescan(scan, nkeys, keys, true,
     										 allow_strat, allow_sync,
     										 allow_pagemode);
     }
    @@ -1073,7 +1074,8 @@ table_rescan_tidrange(TableScanDesc sscan, ItemPointer mintid,
     	/* Ensure table_beginscan_tidrange() was used. */
     	Assert((sscan->rs_flags & SO_TYPE_TIDRANGESCAN) != 0);
     
    -	sscan->rs_rd->rd_tableam->scan_rescan(sscan, NULL, false, false, false, false);
    +	sscan->rs_rd->rd_tableam->scan_rescan(sscan, 0, NULL, false, false, false,
    +										  false);
     	sscan->rs_rd->rd_tableam->scan_set_tidrange(sscan, mintid, maxtid);
     }
     
    @@ -1128,7 +1130,8 @@ extern void table_parallelscan_initialize(Relation rel,
      * Caller must hold a suitable lock on the relation.
      */
     extern TableScanDesc table_beginscan_parallel(Relation relation,
    -											  ParallelTableScanDesc pscan);
    +											  ParallelTableScanDesc pscan,
    +											  int nkeys, ScanKeyData *keys);
     
     /*
      * Begin a parallel tid range scan. `pscan` needs to have been initialized
    -- 
    2.39.5
    
    
    --lqhr7owlpsibhw3z
    Content-Type: text/x-diff; charset=us-ascii
    Content-Disposition: attachment;
    	filename="v4-0003-Simple-quals-push-down-to-table-AMs.patch"