]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Thread flags through begin-scan APIs
authorMelanie Plageman <melanieplageman@gmail.com>
Mon, 30 Mar 2026 16:27:24 +0000 (12:27 -0400)
committerMelanie Plageman <melanieplageman@gmail.com>
Mon, 30 Mar 2026 16:27:24 +0000 (12:27 -0400)
Add an AM user-settable flags parameter to several of the table scan
functions, one table AM callback, and index_beginscan(). This allows
users to pass additional context to be used when building the scan
descriptors.

For index scans, a new flags field is added to IndexFetchTableData, and
the heap AM saves the caller-provided flags there.

This introduces an extension point for follow-up work to pass per-scan
information (such as whether the relation is read-only for the current
query) from the executor to the AM layer.

Author: Melanie Plageman <melanieplageman@gmail.com>
Reviewed-by: Andres Freund <andres@anarazel.de>
Reviewed-by: Tomas Vondra <tomas@vondra.me>
Reviewed-by: David Rowley <dgrowleyml@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/2be31f17-5405-4de9-8d73-90ebc322f7d8%40vondra.me

26 files changed:
contrib/pgrowlocks/pgrowlocks.c
src/backend/access/brin/brin.c
src/backend/access/gin/gininsert.c
src/backend/access/heap/heapam_handler.c
src/backend/access/index/genam.c
src/backend/access/index/indexam.c
src/backend/access/nbtree/nbtsort.c
src/backend/access/table/tableam.c
src/backend/commands/constraint.c
src/backend/commands/copyto.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/executor/execIndexing.c
src/backend/executor/execReplication.c
src/backend/executor/nodeBitmapHeapscan.c
src/backend/executor/nodeIndexonlyscan.c
src/backend/executor/nodeIndexscan.c
src/backend/executor/nodeSamplescan.c
src/backend/executor/nodeSeqscan.c
src/backend/executor/nodeTidrangescan.c
src/backend/partitioning/partbounds.c
src/backend/utils/adt/selfuncs.c
src/include/access/genam.h
src/include/access/heapam.h
src/include/access/relscan.h
src/include/access/tableam.h

index ff3692c87c4f0e243babed8cbdf978caf74bf58a..d164c4c03ad846a8dc5d1b2bf679116869520f44 100644 (file)
@@ -115,7 +115,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
                                           RelationGetRelationName(rel));
 
        /* Scan the relation */
-       scan = table_beginscan(rel, GetActiveSnapshot(), 0, NULL);
+       scan = table_beginscan(rel, GetActiveSnapshot(), 0, NULL, SO_NONE);
        hscan = (HeapScanDesc) scan;
 
        attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc);
index 2a0f8c8e3b8b29b2b729137a4af36bd7369661fd..bdb30752e098cb635f005ee55807e5f35b7c87fc 100644 (file)
@@ -2844,7 +2844,8 @@ _brin_parallel_scan_and_build(BrinBuildState *state,
        indexInfo->ii_Concurrent = brinshared->isconcurrent;
 
        scan = table_beginscan_parallel(heap,
-                                                                       ParallelTableScanFromBrinShared(brinshared));
+                                                                       ParallelTableScanFromBrinShared(brinshared),
+                                                                       SO_NONE);
 
        reltuples = table_index_build_scan(heap, index, indexInfo, true, true,
                                                                           brinbuildCallbackParallel, state, scan);
index e54782d9dd85248aea5f43656367048bf0a9b93a..9d83a4957757bc3190b77db8013c0f8011d18ed6 100644 (file)
@@ -2068,7 +2068,8 @@ _gin_parallel_scan_and_build(GinBuildState *state,
        indexInfo->ii_Concurrent = ginshared->isconcurrent;
 
        scan = table_beginscan_parallel(heap,
-                                                                       ParallelTableScanFromGinBuildShared(ginshared));
+                                                                       ParallelTableScanFromGinBuildShared(ginshared),
+                                                                       SO_NONE);
 
        reltuples = table_index_build_scan(heap, index, indexInfo, true, progress,
                                                                           ginBuildCallbackParallel, state, scan);
index 7c2194b152b7f7384e81cec560fed2cf64de2b63..4de1eab4a732590cf137bcf37afb9d2dfa156427 100644 (file)
@@ -81,11 +81,12 @@ heapam_slot_callbacks(Relation relation)
  */
 
 static IndexFetchTableData *
-heapam_index_fetch_begin(Relation rel)
+heapam_index_fetch_begin(Relation rel, uint32 flags)
 {
        IndexFetchHeapData *hscan = palloc0_object(IndexFetchHeapData);
 
        hscan->xs_base.rel = rel;
+       hscan->xs_base.flags = flags;
        hscan->xs_cbuf = InvalidBuffer;
        hscan->xs_vmbuffer = InvalidBuffer;
 
@@ -763,7 +764,8 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
 
                tableScan = NULL;
                heapScan = NULL;
-               indexScan = index_beginscan(OldHeap, OldIndex, SnapshotAny, NULL, 0, 0);
+               indexScan = index_beginscan(OldHeap, OldIndex, SnapshotAny, NULL, 0, 0,
+                                                                       SO_NONE);
                index_rescan(indexScan, NULL, 0, NULL, 0);
        }
        else
@@ -772,7 +774,8 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
                pgstat_progress_update_param(PROGRESS_REPACK_PHASE,
                                                                         PROGRESS_REPACK_PHASE_SEQ_SCAN_HEAP);
 
-               tableScan = table_beginscan(OldHeap, SnapshotAny, 0, (ScanKey) NULL);
+               tableScan = table_beginscan(OldHeap, SnapshotAny, 0, (ScanKey) NULL,
+                                                                       SO_NONE);
                heapScan = (HeapScanDesc) tableScan;
                indexScan = NULL;
 
index 5e89b86a62c428d4fdb0b38fadb6ade5d2351abd..1408989c5687378233152d1dce3cbcac4cae225a 100644 (file)
@@ -455,7 +455,8 @@ systable_beginscan(Relation heapRelation,
                }
 
                sysscan->iscan = index_beginscan(heapRelation, irel,
-                                                                                snapshot, NULL, nkeys, 0);
+                                                                                snapshot, NULL, nkeys, 0,
+                                                                                SO_NONE);
                index_rescan(sysscan->iscan, idxkey, nkeys, NULL, 0);
                sysscan->scan = NULL;
 
@@ -716,7 +717,8 @@ systable_beginscan_ordered(Relation heapRelation,
                bsysscan = true;
 
        sysscan->iscan = index_beginscan(heapRelation, indexRelation,
-                                                                        snapshot, NULL, nkeys, 0);
+                                                                        snapshot, NULL, nkeys, 0,
+                                                                        SO_NONE);
        index_rescan(sysscan->iscan, idxkey, nkeys, NULL, 0);
        sysscan->scan = NULL;
 
index fbfc33159eb5bc387f42baf8124b320119776800..44496ae0963e1768941f31a8b4740a2211656887 100644 (file)
@@ -258,7 +258,8 @@ index_beginscan(Relation heapRelation,
                                Relation indexRelation,
                                Snapshot snapshot,
                                IndexScanInstrumentation *instrument,
-                               int nkeys, int norderbys)
+                               int nkeys, int norderbys,
+                               uint32 flags)
 {
        IndexScanDesc scan;
 
@@ -285,7 +286,7 @@ index_beginscan(Relation heapRelation,
        scan->instrument = instrument;
 
        /* prepare to fetch index matches from table */
-       scan->xs_heapfetch = table_index_fetch_begin(heapRelation);
+       scan->xs_heapfetch = table_index_fetch_begin(heapRelation, flags);
 
        return scan;
 }
@@ -588,13 +589,17 @@ index_parallelrescan(IndexScanDesc scan)
 /*
  * index_beginscan_parallel - join parallel index scan
  *
+ * flags is a bitmask of ScanOptions affecting the underlying table scan. No
+ * SO_INTERNAL_FLAGS are permitted.
+ *
  * Caller must be holding suitable locks on the heap and the index.
  */
 IndexScanDesc
 index_beginscan_parallel(Relation heaprel, Relation indexrel,
                                                 IndexScanInstrumentation *instrument,
                                                 int nkeys, int norderbys,
-                                                ParallelIndexScanDesc pscan)
+                                                ParallelIndexScanDesc pscan,
+                                                uint32 flags)
 {
        Snapshot        snapshot;
        IndexScanDesc scan;
@@ -616,7 +621,7 @@ index_beginscan_parallel(Relation heaprel, Relation indexrel,
        scan->instrument = instrument;
 
        /* prepare to fetch index matches from table */
-       scan->xs_heapfetch = table_index_fetch_begin(heaprel);
+       scan->xs_heapfetch = table_index_fetch_begin(heaprel, flags);
 
        return scan;
 }
index 47a9bda30c9b1e0d76ff84b9d8a01c20b2c38248..756dfa3dcf47ef75a288702eccc2011823ad588c 100644 (file)
@@ -1928,7 +1928,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),
+                                                                       SO_NONE);
        reltuples = table_index_build_scan(btspool->heap, btspool->index, indexInfo,
                                                                           true, progress, _bt_build_callback,
                                                                           &buildstate, scan);
index dfda1af412ec3b21c09c751e94dbd2382c685fe8..86481d7c029daad8d6c82ea29aa578875deccf07 100644 (file)
@@ -118,7 +118,7 @@ table_beginscan_catalog(Relation relation, int nkeys, ScanKeyData *key)
        Snapshot        snapshot = RegisterSnapshot(GetCatalogSnapshot(relid));
 
        return table_beginscan_common(relation, snapshot, nkeys, key,
-                                                                 NULL, flags);
+                                                                 NULL, flags, SO_NONE);
 }
 
 
@@ -163,10 +163,11 @@ table_parallelscan_initialize(Relation rel, ParallelTableScanDesc pscan,
 }
 
 TableScanDesc
-table_beginscan_parallel(Relation relation, ParallelTableScanDesc pscan)
+table_beginscan_parallel(Relation relation, ParallelTableScanDesc pscan,
+                                                uint32 flags)
 {
        Snapshot        snapshot;
-       uint32          flags = SO_TYPE_SEQSCAN |
+       uint32          internal_flags = SO_TYPE_SEQSCAN |
                SO_ALLOW_STRAT | SO_ALLOW_SYNC | SO_ALLOW_PAGEMODE;
 
        Assert(RelFileLocatorEquals(relation->rd_locator, pscan->phs_locator));
@@ -176,7 +177,7 @@ table_beginscan_parallel(Relation relation, ParallelTableScanDesc pscan)
                /* Snapshot was serialized -- restore it */
                snapshot = RestoreSnapshot((char *) pscan + pscan->phs_snapshot_off);
                RegisterSnapshot(snapshot);
-               flags |= SO_TEMP_SNAPSHOT;
+               internal_flags |= SO_TEMP_SNAPSHOT;
        }
        else
        {
@@ -185,16 +186,17 @@ table_beginscan_parallel(Relation relation, ParallelTableScanDesc pscan)
        }
 
        return table_beginscan_common(relation, snapshot, 0, NULL,
-                                                                 pscan, flags);
+                                                                 pscan, internal_flags, flags);
 }
 
 TableScanDesc
 table_beginscan_parallel_tidrange(Relation relation,
-                                                                 ParallelTableScanDesc pscan)
+                                                                 ParallelTableScanDesc pscan,
+                                                                 uint32 flags)
 {
        Snapshot        snapshot;
-       uint32          flags = SO_TYPE_TIDRANGESCAN | SO_ALLOW_PAGEMODE;
        TableScanDesc sscan;
+       uint32          internal_flags = SO_TYPE_TIDRANGESCAN | SO_ALLOW_PAGEMODE;
 
        Assert(RelFileLocatorEquals(relation->rd_locator, pscan->phs_locator));
 
@@ -206,7 +208,7 @@ table_beginscan_parallel_tidrange(Relation relation,
                /* Snapshot was serialized -- restore it */
                snapshot = RestoreSnapshot((char *) pscan + pscan->phs_snapshot_off);
                RegisterSnapshot(snapshot);
-               flags |= SO_TEMP_SNAPSHOT;
+               internal_flags |= SO_TEMP_SNAPSHOT;
        }
        else
        {
@@ -215,7 +217,7 @@ table_beginscan_parallel_tidrange(Relation relation,
        }
 
        sscan = table_beginscan_common(relation, snapshot, 0, NULL,
-                                                                  pscan, flags);
+                                                                  pscan, internal_flags, flags);
        return sscan;
 }
 
@@ -248,7 +250,7 @@ table_index_fetch_tuple_check(Relation rel,
        bool            found;
 
        slot = table_slot_create(rel, NULL);
-       scan = table_index_fetch_begin(rel);
+       scan = table_index_fetch_begin(rel, SO_NONE);
        found = table_index_fetch_tuple(scan, tid, snapshot, slot, &call_again,
                                                                        all_dead);
        table_index_fetch_end(scan);
index cc11c47b6f234185d768602ae358e8ee18bd8f62..421d8c359f0f97efc014b5d1b1b555469c30318d 100644 (file)
@@ -106,7 +106,8 @@ unique_key_recheck(PG_FUNCTION_ARGS)
         */
        tmptid = checktid;
        {
-               IndexFetchTableData *scan = table_index_fetch_begin(trigdata->tg_relation);
+               IndexFetchTableData *scan = table_index_fetch_begin(trigdata->tg_relation,
+                                                                                                                       SO_NONE);
                bool            call_again = false;
 
                if (!table_index_fetch_tuple(scan, &tmptid, SnapshotSelf, slot,
index faf62d959b4a37295983ea1101f85260ab9792ca..f0e0147c665014da04e8c7205942622df27ce5c9 100644 (file)
@@ -1336,7 +1336,8 @@ CopyRelationTo(CopyToState cstate, Relation rel, Relation root_rel, uint64 *proc
        AttrMap    *map = NULL;
        TupleTableSlot *root_slot = NULL;
 
-       scandesc = table_beginscan(rel, GetActiveSnapshot(), 0, NULL);
+       scandesc = table_beginscan(rel, GetActiveSnapshot(), 0, NULL,
+                                                          SO_NONE);
        slot = table_slot_create(rel, NULL);
 
        /*
index dd00e36c69d87d85281fe237135d6eb1973d3a85..cfb60940f4d8890ea734a8dacb18092ba103c6f0 100644 (file)
@@ -6411,7 +6411,8 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
                 * checking all the constraints.
                 */
                snapshot = RegisterSnapshot(GetLatestSnapshot());
-               scan = table_beginscan(oldrel, snapshot, 0, NULL);
+               scan = table_beginscan(oldrel, snapshot, 0, NULL,
+                                                          SO_NONE);
 
                /*
                 * Switch to per-tuple memory context and reset it for each tuple
@@ -13982,8 +13983,8 @@ validateForeignKeyConstraint(char *conname,
         */
        snapshot = RegisterSnapshot(GetLatestSnapshot());
        slot = table_slot_create(rel, NULL);
-       scan = table_beginscan(rel, snapshot, 0, NULL);
-
+       scan = table_beginscan(rel, snapshot, 0, NULL,
+                                                  SO_NONE);
        perTupCxt = AllocSetContextCreate(CurrentMemoryContext,
                                                                          "validateForeignKeyConstraint",
                                                                          ALLOCSET_SMALL_SIZES);
@@ -22884,7 +22885,8 @@ MergePartitionsMoveRows(List **wqueue, List *mergingPartitions, Relation newPart
 
                /* Scan through the rows. */
                snapshot = RegisterSnapshot(GetLatestSnapshot());
-               scan = table_beginscan(mergingPartition, snapshot, 0, NULL);
+               scan = table_beginscan(mergingPartition, snapshot, 0, NULL,
+                                                          SO_NONE);
 
                /*
                 * Switch to per-tuple memory context and reset it for each tuple
@@ -23348,7 +23350,8 @@ SplitPartitionMoveRows(List **wqueue, Relation rel, Relation splitRel,
 
        /* Scan through the rows. */
        snapshot = RegisterSnapshot(GetLatestSnapshot());
-       scan = table_beginscan(splitRel, snapshot, 0, NULL);
+       scan = table_beginscan(splitRel, snapshot, 0, NULL,
+                                                  SO_NONE);
 
        /*
         * Switch to per-tuple memory context and reset it for each tuple
index 3dab6bb5a797340410aa50ae2215b1f4b7377aa6..cd38e9cddf46b260b83aebc8efcc9706dd331091 100644 (file)
@@ -3185,7 +3185,8 @@ validateDomainNotNullConstraint(Oid domainoid)
 
                /* Scan all tuples in this relation */
                snapshot = RegisterSnapshot(GetLatestSnapshot());
-               scan = table_beginscan(testrel, snapshot, 0, NULL);
+               scan = table_beginscan(testrel, snapshot, 0, NULL,
+                                                          SO_NONE);
                slot = table_slot_create(testrel, NULL);
                while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
                {
@@ -3266,7 +3267,8 @@ validateDomainCheckConstraint(Oid domainoid, const char *ccbin, LOCKMODE lockmod
 
                /* Scan all tuples in this relation */
                snapshot = RegisterSnapshot(GetLatestSnapshot());
-               scan = table_beginscan(testrel, snapshot, 0, NULL);
+               scan = table_beginscan(testrel, snapshot, 0, NULL,
+                                                          SO_NONE);
                slot = table_slot_create(testrel, NULL);
                while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
                {
index 9d071e495c64e1c485e3f6c4cc6aee6840c28868..cc6eb3a6ee9f0c3387bfb0f67b7bffce7fb80ae0 100644 (file)
@@ -815,7 +815,9 @@ check_exclusion_or_unique_constraint(Relation heap, Relation index,
 retry:
        conflict = false;
        found_self = false;
-       index_scan = index_beginscan(heap, index, &DirtySnapshot, NULL, indnkeyatts, 0);
+       index_scan = index_beginscan(heap, index,
+                                                                &DirtySnapshot, NULL, indnkeyatts, 0,
+                                                                SO_NONE);
        index_rescan(index_scan, scankeys, indnkeyatts, NULL, 0);
 
        while (index_getnext_slot(index_scan, ForwardScanDirection, existing_slot))
index 2497ee7edc5108b319e8bff42c7b436297e52dba..fea8991cb04371a1d0f7be198cf814b677b09fb9 100644 (file)
@@ -205,7 +205,8 @@ RelationFindReplTupleByIndex(Relation rel, Oid idxoid,
        skey_attoff = build_replindex_scan_key(skey, rel, idxrel, searchslot);
 
        /* Start an index scan. */
-       scan = index_beginscan(rel, idxrel, &snap, NULL, skey_attoff, 0);
+       scan = index_beginscan(rel, idxrel,
+                                                  &snap, NULL, skey_attoff, 0, SO_NONE);
 
 retry:
        found = false;
@@ -383,7 +384,8 @@ RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode,
 
        /* Start a heap scan. */
        InitDirtySnapshot(snap);
-       scan = table_beginscan(rel, &snap, 0, NULL);
+       scan = table_beginscan(rel, &snap, 0, NULL,
+                                                  SO_NONE);
        scanslot = table_slot_create(rel, NULL);
 
 retry:
@@ -602,7 +604,8 @@ RelationFindDeletedTupleInfoSeq(Relation rel, TupleTableSlot *searchslot,
         * not yet committed or those just committed prior to the scan are
         * excluded in update_most_recent_deletion_info().
         */
-       scan = table_beginscan(rel, SnapshotAny, 0, NULL);
+       scan = table_beginscan(rel, SnapshotAny, 0, NULL,
+                                                  SO_NONE);
        scanslot = table_slot_create(rel, NULL);
 
        table_rescan(scan, NULL);
@@ -666,7 +669,8 @@ RelationFindDeletedTupleInfoByIndex(Relation rel, Oid idxoid,
         * not yet committed or those just committed prior to the scan are
         * excluded in update_most_recent_deletion_info().
         */
-       scan = index_beginscan(rel, idxrel, SnapshotAny, NULL, skey_attoff, 0);
+       scan = index_beginscan(rel, idxrel,
+                                                  SnapshotAny, NULL, skey_attoff, 0, SO_NONE);
 
        index_rescan(scan, skey, skey_attoff, NULL, 0);
 
index 7cf8d23c7422b76e21340ede5f3d86382aafeb66..69683d81527853bb58d23d99980ed8edc2547335 100644 (file)
@@ -148,7 +148,8 @@ BitmapTableScanSetup(BitmapHeapScanState *node)
                        table_beginscan_bm(node->ss.ss_currentRelation,
                                                           node->ss.ps.state->es_snapshot,
                                                           0,
-                                                          NULL);
+                                                          NULL,
+                                                          SO_NONE);
        }
 
        node->ss.ss_currentScanDesc->st.rs_tbmiterator = tbmiterator;
index 9eab81fd1c85b8fecaa95c58deb503775e653aa1..02df40f32c5fd5e432a9b972dbcbd361ef5c66f5 100644 (file)
@@ -95,7 +95,8 @@ IndexOnlyNext(IndexOnlyScanState *node)
                                                                   estate->es_snapshot,
                                                                   node->ioss_Instrument,
                                                                   node->ioss_NumScanKeys,
-                                                                  node->ioss_NumOrderByKeys);
+                                                                  node->ioss_NumOrderByKeys,
+                                                                  SO_NONE);
 
                node->ioss_ScanDesc = scandesc;
 
@@ -794,7 +795,8 @@ ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node,
                                                                 node->ioss_Instrument,
                                                                 node->ioss_NumScanKeys,
                                                                 node->ioss_NumOrderByKeys,
-                                                                piscan);
+                                                                piscan,
+                                                                SO_NONE);
        node->ioss_ScanDesc->xs_want_itup = true;
        node->ioss_VMBuffer = InvalidBuffer;
 
@@ -860,7 +862,8 @@ ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node,
                                                                 node->ioss_Instrument,
                                                                 node->ioss_NumScanKeys,
                                                                 node->ioss_NumOrderByKeys,
-                                                                piscan);
+                                                                piscan,
+                                                                SO_NONE);
        node->ioss_ScanDesc->xs_want_itup = true;
 
        /*
index 06143e94c5a44daed7724ac7ea8b033305dfbd34..3c0b8daf664b01c772c1a3a25c3bea557097e1c5 100644 (file)
@@ -113,7 +113,8 @@ IndexNext(IndexScanState *node)
                                                                   estate->es_snapshot,
                                                                   node->iss_Instrument,
                                                                   node->iss_NumScanKeys,
-                                                                  node->iss_NumOrderByKeys);
+                                                                  node->iss_NumOrderByKeys,
+                                                                  SO_NONE);
 
                node->iss_ScanDesc = scandesc;
 
@@ -209,7 +210,8 @@ IndexNextWithReorder(IndexScanState *node)
                                                                   estate->es_snapshot,
                                                                   node->iss_Instrument,
                                                                   node->iss_NumScanKeys,
-                                                                  node->iss_NumOrderByKeys);
+                                                                  node->iss_NumOrderByKeys,
+                                                                  SO_NONE);
 
                node->iss_ScanDesc = scandesc;
 
@@ -1730,7 +1732,8 @@ ExecIndexScanInitializeDSM(IndexScanState *node,
                                                                 node->iss_Instrument,
                                                                 node->iss_NumScanKeys,
                                                                 node->iss_NumOrderByKeys,
-                                                                piscan);
+                                                                piscan,
+                                                                SO_NONE);
 
        /*
         * If no run-time keys to calculate or they are ready, go ahead and pass
@@ -1794,7 +1797,8 @@ ExecIndexScanInitializeWorker(IndexScanState *node,
                                                                 node->iss_Instrument,
                                                                 node->iss_NumScanKeys,
                                                                 node->iss_NumOrderByKeys,
-                                                                piscan);
+                                                                piscan,
+                                                                SO_NONE);
 
        /*
         * If no run-time keys to calculate or they are ready, go ahead and pass
index 6b0d65f752f17eb7019038827e0d8cb308edfd31..cf32df33d82fbf24ba9ef5760fc8462b6952b533 100644 (file)
@@ -298,7 +298,8 @@ tablesample_init(SampleScanState *scanstate)
                                                                         0, NULL,
                                                                         scanstate->use_bulkread,
                                                                         allow_sync,
-                                                                        scanstate->use_pagemode);
+                                                                        scanstate->use_pagemode,
+                                                                        SO_NONE);
        }
        else
        {
index 8f219f60a9361f1812c1799eb4c8733919672ba7..09ccc65de1ce6304d1c706aaf7d5bb3f431d131a 100644 (file)
@@ -71,7 +71,8 @@ SeqNext(SeqScanState *node)
                 */
                scandesc = table_beginscan(node->ss.ss_currentRelation,
                                                                   estate->es_snapshot,
-                                                                  0, NULL);
+                                                                  0, NULL,
+                                                                  SO_NONE);
                node->ss.ss_currentScanDesc = scandesc;
        }
 
@@ -375,7 +376,8 @@ 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,
+                                                                SO_NONE);
 }
 
 /* ----------------------------------------------------------------
@@ -408,5 +410,6 @@ 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,
+                                                                SO_NONE);
 }
index 617713bde043dca46a71b2e4abb7cec603d8a32f..084e4c6ec90c2161bf1596ec39aca1c061bd9356 100644 (file)
@@ -245,7 +245,8 @@ TidRangeNext(TidRangeScanState *node)
                        scandesc = table_beginscan_tidrange(node->ss.ss_currentRelation,
                                                                                                estate->es_snapshot,
                                                                                                &node->trss_mintid,
-                                                                                               &node->trss_maxtid);
+                                                                                               &node->trss_maxtid,
+                                                                                               SO_NONE);
                        node->ss.ss_currentScanDesc = scandesc;
                }
                else
@@ -460,7 +461,7 @@ ExecTidRangeScanInitializeDSM(TidRangeScanState *node, ParallelContext *pcxt)
        shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
        node->ss.ss_currentScanDesc =
                table_beginscan_parallel_tidrange(node->ss.ss_currentRelation,
-                                                                                 pscan);
+                                                                                 pscan, SO_NONE);
 }
 
 /* ----------------------------------------------------------------
@@ -494,5 +495,5 @@ ExecTidRangeScanInitializeWorker(TidRangeScanState *node,
        pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
        node->ss.ss_currentScanDesc =
                table_beginscan_parallel_tidrange(node->ss.ss_currentRelation,
-                                                                                 pscan);
+                                                                                 pscan, SO_NONE);
 }
index 0ca312ac27dad0775f5127a7f30552525d1234f6..f867d1b75a54e07cf2c4f24a5f0aa83de2fc9cea 100644 (file)
@@ -3362,7 +3362,8 @@ check_default_partition_contents(Relation parent, Relation default_rel,
                econtext = GetPerTupleExprContext(estate);
                snapshot = RegisterSnapshot(GetLatestSnapshot());
                tupslot = table_slot_create(part_rel, &estate->es_tupleTable);
-               scan = table_beginscan(part_rel, snapshot, 0, NULL);
+               scan = table_beginscan(part_rel, snapshot, 0, NULL,
+                                                          SO_NONE);
 
                /*
                 * Switch to per-tuple memory context and reset it for each tuple
index 53f85ccde015c0bcee9495a6457298ce1a15a0fa..4160d2d6e24a8e6b406fa9297e1d3fa8208c6be1 100644 (file)
@@ -7178,7 +7178,8 @@ get_actual_variable_endpoint(Relation heapRel,
 
        index_scan = index_beginscan(heapRel, indexRel,
                                                                 &SnapshotNonVacuumable, NULL,
-                                                                1, 0);
+                                                                1, 0,
+                                                                SO_NONE);
        /* Set it up for index-only scan */
        index_scan->xs_want_itup = true;
        index_rescan(index_scan, scankeys, 1, NULL, 0);
index 1a27bf060b30e7cc4757ea836c935cec57b495be..b69320a7fc82c29352823b639eb674908c8dd6ef 100644 (file)
@@ -158,7 +158,8 @@ extern IndexScanDesc index_beginscan(Relation heapRelation,
                                                                         Relation indexRelation,
                                                                         Snapshot snapshot,
                                                                         IndexScanInstrumentation *instrument,
-                                                                        int nkeys, int norderbys);
+                                                                        int nkeys, int norderbys,
+                                                                        uint32 flags);
 extern IndexScanDesc index_beginscan_bitmap(Relation indexRelation,
                                                                                        Snapshot snapshot,
                                                                                        IndexScanInstrumentation *instrument,
@@ -184,7 +185,8 @@ extern IndexScanDesc index_beginscan_parallel(Relation heaprel,
                                                                                          Relation indexrel,
                                                                                          IndexScanInstrumentation *instrument,
                                                                                          int nkeys, int norderbys,
-                                                                                         ParallelIndexScanDesc pscan);
+                                                                                         ParallelIndexScanDesc pscan,
+                                                                                         uint32 flags);
 extern ItemPointer index_getnext_tid(IndexScanDesc scan,
                                                                         ScanDirection direction);
 extern bool index_fetch_heap(IndexScanDesc scan, TupleTableSlot *slot);
index 53e86c0d6e137929cec1c9f6972f09e4378d789e..4e982d768891b5ce274074a74b456ef5544a189d 100644 (file)
@@ -95,10 +95,7 @@ typedef struct HeapScanDescData
         */
        ParallelBlockTableScanWorkerData *rs_parallelworkerdata;
 
-       /*
-        * For sequential scans and bitmap heap scans. The current heap block's
-        * corresponding page in the visibility map.
-        */
+       /* Current heap block's corresponding page in the visibility map */
        Buffer          rs_vmbuffer;
 
        /* these fields only used in page-at-a-time mode and for bitmap scans */
index ce340c076f84f723439a8e2353784ec20c37cd89..960abf6c214771096ad3f0fcc7b382bba2328d48 100644 (file)
@@ -122,6 +122,12 @@ typedef struct ParallelBlockTableScanWorkerData *ParallelBlockTableScanWorker;
 typedef struct IndexFetchTableData
 {
        Relation        rel;
+
+       /*
+        * Bitmask of ScanOptions affecting the relation. No SO_INTERNAL_FLAGS are
+        * permitted.
+        */
+       uint32          flags;
 } IndexFetchTableData;
 
 struct IndexScanInstrumentation;
index 3b017e043a0082719207197d64d87016fa6c2785..cd14f242d65e7e591d51865f58a0456c30517be3 100644 (file)
@@ -45,6 +45,8 @@ typedef struct ValidateIndexState ValidateIndexState;
  */
 typedef enum ScanOptions
 {
+       SO_NONE = 0,
+
        /* one of SO_TYPE_* may be specified */
        SO_TYPE_SEQSCAN = 1 << 0,
        SO_TYPE_BITMAPSCAN = 1 << 1,
@@ -65,6 +67,19 @@ typedef enum ScanOptions
        SO_TEMP_SNAPSHOT = 1 << 9,
 }                      ScanOptions;
 
+/*
+ * Mask of flags that are set internally by the table scan functions and
+ * shouldn't be passed by callers. Some of these are effectively set by callers
+ * through parameters to table scan functions (e.g. SO_ALLOW_STRAT/allow_strat),
+ * however, for now, retain tight control over them and don't allow users to
+ * pass these themselves to table scan functions.
+ */
+#define SO_INTERNAL_FLAGS \
+       (SO_TYPE_SEQSCAN | SO_TYPE_BITMAPSCAN | SO_TYPE_SAMPLESCAN | \
+        SO_TYPE_TIDSCAN | SO_TYPE_TIDRANGESCAN | SO_TYPE_ANALYZE | \
+        SO_ALLOW_STRAT | SO_ALLOW_SYNC | SO_ALLOW_PAGEMODE | \
+        SO_TEMP_SNAPSHOT)
+
 /*
  * Result codes for table_{update,delete,lock_tuple}, and for visibility
  * routines inside table AMs.
@@ -324,8 +339,9 @@ typedef struct TableAmRoutine
         * `flags` is a bitmask indicating the type of scan (ScanOptions's
         * SO_TYPE_*, currently only one may be specified), options controlling
         * the scan's behaviour (ScanOptions's SO_ALLOW_*, several may be
-        * specified, an AM may ignore unsupported ones) and whether the snapshot
-        * needs to be deallocated at scan_end (ScanOptions's SO_TEMP_SNAPSHOT).
+        * specified, an AM may ignore unsupported ones), whether the snapshot
+        * needs to be deallocated at scan_end (ScanOptions's SO_TEMP_SNAPSHOT),
+        * and any number of the other ScanOptions values.
         */
        TableScanDesc (*scan_begin) (Relation rel,
                                                                 Snapshot snapshot,
@@ -421,9 +437,12 @@ typedef struct TableAmRoutine
         * IndexFetchTableData, which the AM will typically embed in a larger
         * structure with additional information.
         *
+        * flags is a bitmask of ScanOptions affecting underlying table scan
+        * behavior. See scan_begin() for more information on passing these.
+        *
         * Tuples for an index scan can then be fetched via index_fetch_tuple.
         */
-       struct IndexFetchTableData *(*index_fetch_begin) (Relation rel);
+       struct IndexFetchTableData *(*index_fetch_begin) (Relation rel, uint32 flags);
 
        /*
         * Reset index fetch. Typically this will release cross index fetch
@@ -874,12 +893,19 @@ extern TupleTableSlot *table_slot_create(Relation relation, List **reglist);
  * A wrapper around the Table Access Method scan_begin callback, to centralize
  * error checking. All calls to ->scan_begin() should go through this
  * function.
+ *
+ * The caller-provided user_flags are validated against SO_INTERNAL_FLAGS to
+ * catch callers that accidentally pass scan-type or other internal flags.
  */
 static TableScanDesc
 table_beginscan_common(Relation rel, Snapshot snapshot, int nkeys,
                                           ScanKeyData *key, ParallelTableScanDesc pscan,
-                                          uint32 flags)
+                                          uint32 flags, uint32 user_flags)
 {
+       Assert((user_flags & SO_INTERNAL_FLAGS) == 0);
+       Assert((flags & ~SO_INTERNAL_FLAGS) == 0);
+       flags |= user_flags;
+
        /*
         * We don't allow scans to be started while CheckXidAlive is set, except
         * via systable_beginscan() et al.  See detailed comments in xact.c where
@@ -894,15 +920,18 @@ table_beginscan_common(Relation rel, Snapshot snapshot, int nkeys,
 /*
  * Start a scan of `rel`. Returned tuples pass a visibility test of
  * `snapshot`, and if nkeys != 0, the results are filtered by those scan keys.
+ *
+ * flags is a bitmask of ScanOptions. No SO_INTERNAL_FLAGS are permitted.
  */
 static inline TableScanDesc
 table_beginscan(Relation rel, Snapshot snapshot,
-                               int nkeys, ScanKeyData *key)
+                               int nkeys, ScanKeyData *key, uint32 flags)
 {
-       uint32          flags = SO_TYPE_SEQSCAN |
+       uint32          internal_flags = SO_TYPE_SEQSCAN |
                SO_ALLOW_STRAT | SO_ALLOW_SYNC | SO_ALLOW_PAGEMODE;
 
-       return table_beginscan_common(rel, snapshot, nkeys, key, NULL, flags);
+       return table_beginscan_common(rel, snapshot, nkeys, key, NULL,
+                                                                 internal_flags, flags);
 }
 
 /*
@@ -931,7 +960,8 @@ table_beginscan_strat(Relation rel, Snapshot snapshot,
        if (allow_sync)
                flags |= SO_ALLOW_SYNC;
 
-       return table_beginscan_common(rel, snapshot, nkeys, key, NULL, flags);
+       return table_beginscan_common(rel, snapshot, nkeys, key, NULL,
+                                                                 flags, SO_NONE);
 }
 
 /*
@@ -939,14 +969,17 @@ table_beginscan_strat(Relation rel, Snapshot snapshot,
  * TableScanDesc for a bitmap heap scan.  Although that scan technology is
  * really quite unlike a standard seqscan, there is just enough commonality to
  * make it worth using the same data structure.
+ *
+ * flags is a bitmask of ScanOptions. No SO_INTERNAL_FLAGS are permitted.
  */
 static inline TableScanDesc
 table_beginscan_bm(Relation rel, Snapshot snapshot,
-                                  int nkeys, ScanKeyData *key)
+                                  int nkeys, ScanKeyData *key, uint32 flags)
 {
-       uint32          flags = SO_TYPE_BITMAPSCAN | SO_ALLOW_PAGEMODE;
+       uint32          internal_flags = SO_TYPE_BITMAPSCAN | SO_ALLOW_PAGEMODE;
 
-       return table_beginscan_common(rel, snapshot, nkeys, key, NULL, flags);
+       return table_beginscan_common(rel, snapshot, nkeys, key, NULL,
+                                                                 internal_flags, flags);
 }
 
 /*
@@ -955,23 +988,26 @@ table_beginscan_bm(Relation rel, Snapshot snapshot,
  * using the same data structure although the behavior is rather different.
  * In addition to the options offered by table_beginscan_strat, this call
  * also allows control of whether page-mode visibility checking is used.
+ *
+ * flags is a bitmask of ScanOptions. No SO_INTERNAL_FLAGS are permitted.
  */
 static inline TableScanDesc
 table_beginscan_sampling(Relation rel, Snapshot snapshot,
                                                 int nkeys, ScanKeyData *key,
                                                 bool allow_strat, bool allow_sync,
-                                                bool allow_pagemode)
+                                                bool allow_pagemode, uint32 flags)
 {
-       uint32          flags = SO_TYPE_SAMPLESCAN;
+       uint32          internal_flags = SO_TYPE_SAMPLESCAN;
 
        if (allow_strat)
-               flags |= SO_ALLOW_STRAT;
+               internal_flags |= SO_ALLOW_STRAT;
        if (allow_sync)
-               flags |= SO_ALLOW_SYNC;
+               internal_flags |= SO_ALLOW_SYNC;
        if (allow_pagemode)
-               flags |= SO_ALLOW_PAGEMODE;
+               internal_flags |= SO_ALLOW_PAGEMODE;
 
-       return table_beginscan_common(rel, snapshot, nkeys, key, NULL, flags);
+       return table_beginscan_common(rel, snapshot, nkeys, key, NULL,
+                                                                 internal_flags, flags);
 }
 
 /*
@@ -984,7 +1020,8 @@ table_beginscan_tid(Relation rel, Snapshot snapshot)
 {
        uint32          flags = SO_TYPE_TIDSCAN;
 
-       return table_beginscan_common(rel, snapshot, 0, NULL, NULL, flags);
+       return table_beginscan_common(rel, snapshot, 0, NULL, NULL,
+                                                                 flags, SO_NONE);
 }
 
 /*
@@ -997,7 +1034,8 @@ table_beginscan_analyze(Relation rel)
 {
        uint32          flags = SO_TYPE_ANALYZE;
 
-       return table_beginscan_common(rel, NULL, 0, NULL, NULL, flags);
+       return table_beginscan_common(rel, NULL, 0, NULL, NULL,
+                                                                 flags, SO_NONE);
 }
 
 /*
@@ -1058,16 +1096,19 @@ table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableS
 /*
  * table_beginscan_tidrange is the entry point for setting up a TableScanDesc
  * for a TID range scan.
+ *
+ * flags is a bitmask of ScanOptions. No SO_INTERNAL_FLAGS are permitted.
  */
 static inline TableScanDesc
 table_beginscan_tidrange(Relation rel, Snapshot snapshot,
                                                 ItemPointer mintid,
-                                                ItemPointer maxtid)
+                                                ItemPointer maxtid, uint32 flags)
 {
        TableScanDesc sscan;
-       uint32          flags = SO_TYPE_TIDRANGESCAN | SO_ALLOW_PAGEMODE;
+       uint32          internal_flags = SO_TYPE_TIDRANGESCAN | SO_ALLOW_PAGEMODE;
 
-       sscan = table_beginscan_common(rel, snapshot, 0, NULL, NULL, flags);
+       sscan = table_beginscan_common(rel, snapshot, 0, NULL, NULL,
+                                                                  internal_flags, flags);
 
        /* Set the range of TIDs to scan */
        sscan->rs_rd->rd_tableam->scan_set_tidrange(sscan, mintid, maxtid);
@@ -1139,20 +1180,26 @@ extern void table_parallelscan_initialize(Relation rel,
  * table_parallelscan_initialize(), for the same relation. The initialization
  * does not need to have happened in this backend.
  *
+ * flags is a bitmask of ScanOptions. No SO_INTERNAL_FLAGS are permitted.
+ *
  * Caller must hold a suitable lock on the relation.
  */
 extern TableScanDesc table_beginscan_parallel(Relation relation,
-                                                                                         ParallelTableScanDesc pscan);
+                                                                                         ParallelTableScanDesc pscan,
+                                                                                         uint32 flags);
 
 /*
  * Begin a parallel tid range scan. `pscan` needs to have been initialized
  * with table_parallelscan_initialize(), for the same relation. The
  * initialization does not need to have happened in this backend.
  *
+ * flags is a bitmask of ScanOptions. No SO_INTERNAL_FLAGS are permitted.
+ *
  * Caller must hold a suitable lock on the relation.
  */
 extern TableScanDesc table_beginscan_parallel_tidrange(Relation relation,
-                                                                                                          ParallelTableScanDesc pscan);
+                                                                                                          ParallelTableScanDesc pscan,
+                                                                                                          uint32 flags);
 
 /*
  * Restart a parallel scan.  Call this in the leader process.  Caller is
@@ -1175,11 +1222,15 @@ table_parallelscan_reinitialize(Relation rel, ParallelTableScanDesc pscan)
  * Prepare to fetch tuples from the relation, as needed when fetching tuples
  * for an index scan.
  *
+ * flags is a bitmask of ScanOptions. No SO_INTERNAL_FLAGS are permitted.
+ *
  * Tuples for an index scan can then be fetched via table_index_fetch_tuple().
  */
 static inline IndexFetchTableData *
-table_index_fetch_begin(Relation rel)
+table_index_fetch_begin(Relation rel, uint32 flags)
 {
+       Assert((flags & SO_INTERNAL_FLAGS) == 0);
+
        /*
         * We don't allow scans to be started while CheckXidAlive is set, except
         * via systable_beginscan() et al.  See detailed comments in xact.c where
@@ -1188,7 +1239,7 @@ table_index_fetch_begin(Relation rel)
        if (unlikely(TransactionIdIsValid(CheckXidAlive) && !bsysscan))
                elog(ERROR, "scan started during logical decoding");
 
-       return rel->rd_tableam->index_fetch_begin(rel);
+       return rel->rd_tableam->index_fetch_begin(rel, flags);
 }
 
 /*