From 105c2c2c0057ee9945cf6ec1c32061f617f627a2 Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Mon, 2 Mar 2026 16:31:33 -0500 Subject: [PATCH v46 3/5] Pass down information on table modification to scan node Pass down information to sequential scan, index [only] scan, bitmap table scan, sample scan, and TID range scan nodes on whether or not the query modifies the relation being scanned. A later commit will use this information to update the VM during on-access pruning only if the relation is not modified by the query. Author: Melanie Plageman Reviewed-by: Andres Freund Reviewed-by: Andrey Borodin Reviewed-by: Tomas Vondra Reviewed-by: Chao Li Discussion: https://postgr.es/m/4379FDA3-9446-4E2C-9C15-32EFE8D4F31B%40yandex-team.ru --- src/backend/executor/execUtils.c | 8 ++++++++ src/backend/executor/nodeBitmapHeapscan.c | 3 ++- src/backend/executor/nodeIndexonlyscan.c | 9 ++++++--- src/backend/executor/nodeIndexscan.c | 12 ++++++++---- src/backend/executor/nodeSamplescan.c | 3 ++- src/backend/executor/nodeSeqscan.c | 10 +++++++--- src/backend/executor/nodeTidrangescan.c | 11 ++++++++--- src/include/access/tableam.h | 3 +++ src/include/executor/executor.h | 2 ++ 9 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 9886ab06b69..d2ffe28e010 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -736,6 +736,14 @@ ExecRelationIsTargetRelation(EState *estate, Index scanrelid) return list_member_int(estate->es_plannedstmt->resultRelations, scanrelid); } +/* Return true if the scan node's relation is not modified by the query */ +bool +ScanRelIsReadOnly(ScanState *ss) +{ + return !bms_is_member(((Scan *) ss->ps.plan)->scanrelid, + ss->ps.state->es_plannedstmt->modifiedRelids); +} + /* ---------------------------------------------------------------- * ExecOpenScanRelation * diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index e58bb02db43..7096e6f8645 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -149,7 +149,8 @@ BitmapTableScanSetup(BitmapHeapScanState *node) node->ss.ps.state->es_snapshot, 0, NULL, - 0 /* flags */ ); + ScanRelIsReadOnly(&node->ss) ? + SO_HINT_REL_READ_ONLY : 0); } node->ss.ss_currentScanDesc->st.rs_tbmiterator = tbmiterator; diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c index f8a6671793f..3971e54d7da 100644 --- a/src/backend/executor/nodeIndexonlyscan.c +++ b/src/backend/executor/nodeIndexonlyscan.c @@ -96,7 +96,8 @@ IndexOnlyNext(IndexOnlyScanState *node) node->ioss_Instrument, node->ioss_NumScanKeys, node->ioss_NumOrderByKeys, - 0 /* flags */ ); + ScanRelIsReadOnly(&node->ss) ? + SO_HINT_REL_READ_ONLY : 0); node->ioss_ScanDesc = scandesc; @@ -796,7 +797,8 @@ ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node, node->ioss_NumScanKeys, node->ioss_NumOrderByKeys, piscan, - 0 /* flags */ ); + ScanRelIsReadOnly(&node->ss) ? + SO_HINT_REL_READ_ONLY : 0); node->ioss_ScanDesc->xs_want_itup = true; node->ioss_VMBuffer = InvalidBuffer; @@ -863,7 +865,8 @@ ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, node->ioss_NumScanKeys, node->ioss_NumOrderByKeys, piscan, - 0 /* flags */ ); + ScanRelIsReadOnly(&node->ss) ? + SO_HINT_REL_READ_ONLY : 0); node->ioss_ScanDesc->xs_want_itup = true; /* diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 3df091ac000..09df10dd78a 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -114,7 +114,8 @@ IndexNext(IndexScanState *node) node->iss_Instrument, node->iss_NumScanKeys, node->iss_NumOrderByKeys, - 0 /* flags */ ); + ScanRelIsReadOnly(&node->ss) ? + SO_HINT_REL_READ_ONLY : 0); node->iss_ScanDesc = scandesc; @@ -211,7 +212,8 @@ IndexNextWithReorder(IndexScanState *node) node->iss_Instrument, node->iss_NumScanKeys, node->iss_NumOrderByKeys, - 0 /* flags */ ); + ScanRelIsReadOnly(&node->ss) ? + SO_HINT_REL_READ_ONLY : 0); node->iss_ScanDesc = scandesc; @@ -1733,7 +1735,8 @@ ExecIndexScanInitializeDSM(IndexScanState *node, node->iss_NumScanKeys, node->iss_NumOrderByKeys, piscan, - 0 /* flags */ ); + ScanRelIsReadOnly(&node->ss) ? + SO_HINT_REL_READ_ONLY : 0); /* * If no run-time keys to calculate or they are ready, go ahead and pass @@ -1798,7 +1801,8 @@ ExecIndexScanInitializeWorker(IndexScanState *node, node->iss_NumScanKeys, node->iss_NumOrderByKeys, piscan, - 0 /* flags */ ); + ScanRelIsReadOnly(&node->ss) ? + SO_HINT_REL_READ_ONLY : 0); /* * If no run-time keys to calculate or they are ready, go ahead and pass diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c index f0e14e53fab..98fab36fbdc 100644 --- a/src/backend/executor/nodeSamplescan.c +++ b/src/backend/executor/nodeSamplescan.c @@ -299,7 +299,8 @@ tablesample_init(SampleScanState *scanstate) scanstate->use_bulkread, allow_sync, scanstate->use_pagemode, - 0 /* flags */ ); + ScanRelIsReadOnly(&scanstate->ss) ? + SO_HINT_REL_READ_ONLY : 0); } else { diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index eaa8cfb6a1a..2f4c18051cd 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -72,7 +72,8 @@ SeqNext(SeqScanState *node) scandesc = table_beginscan(node->ss.ss_currentRelation, estate->es_snapshot, 0, NULL, - 0 /* flags */ ); + ScanRelIsReadOnly(&node->ss) ? + SO_HINT_REL_READ_ONLY : 0); node->ss.ss_currentScanDesc = scandesc; } @@ -375,9 +376,11 @@ ExecSeqScanInitializeDSM(SeqScanState *node, pscan, 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, - 0 /* flags */ ); + ScanRelIsReadOnly(&node->ss) ? + SO_HINT_REL_READ_ONLY : 0); } /* ---------------------------------------------------------------- @@ -411,5 +414,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, - 0 /* flags */ ); + ScanRelIsReadOnly(&node->ss) ? + SO_HINT_REL_READ_ONLY : 0); } diff --git a/src/backend/executor/nodeTidrangescan.c b/src/backend/executor/nodeTidrangescan.c index 6f63e9f80d0..f83a72e3635 100644 --- a/src/backend/executor/nodeTidrangescan.c +++ b/src/backend/executor/nodeTidrangescan.c @@ -246,7 +246,8 @@ TidRangeNext(TidRangeScanState *node) estate->es_snapshot, &node->trss_mintid, &node->trss_maxtid, - 0 /* flags */ ); + ScanRelIsReadOnly(&node->ss) ? + SO_HINT_REL_READ_ONLY : 0); node->ss.ss_currentScanDesc = scandesc; } else @@ -461,7 +462,9 @@ 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, 0 /* flags */ ); + pscan, + ScanRelIsReadOnly(&node->ss) ? + SO_HINT_REL_READ_ONLY : 0); } /* ---------------------------------------------------------------- @@ -495,5 +498,7 @@ 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, 0 /* flags */ ); + pscan, + ScanRelIsReadOnly(&node->ss) ? + SO_HINT_REL_READ_ONLY : 0); } diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h index ce5176bdf69..014c686a5de 100644 --- a/src/include/access/tableam.h +++ b/src/include/access/tableam.h @@ -63,6 +63,9 @@ typedef enum ScanOptions /* unregister snapshot at scan end? */ SO_TEMP_SNAPSHOT = 1 << 9, + + /* set if the query doesn't modify the relation */ + SO_HINT_REL_READ_ONLY = 1 << 10, } ScanOptions; /* diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 07f4b1f7490..7979a17e4ec 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -690,6 +690,8 @@ extern void ExecCreateScanSlotFromOuterPlan(EState *estate, extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid); +extern bool ScanRelIsReadOnly(ScanState *ss); + extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags); extern void ExecInitRangeTable(EState *estate, List *rangeTable, List *permInfos, -- 2.43.0