From 1ca6d596a776c850406f338052066b4e0e6a8493 Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@vondra.me>
Date: Wed, 1 Apr 2026 20:21:36 +0200
Subject: [PATCH v7 6/6] fixup: show prefetch stats for TidRangeScan

---
 src/backend/commands/explain.c          |  3 -
 src/backend/executor/execParallel.c     | 18 ++---
 src/backend/executor/nodeTidrangescan.c | 94 ++++++++++++++++++-------
 3 files changed, 77 insertions(+), 38 deletions(-)

diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 99b64d87126..4491270b387 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -4120,9 +4120,6 @@ show_scan_io_usage(ScanState *planstate, ExplainState *es)
 				SharedTidRangeScanInstrumentation *sinstrument
 					= ((TidRangeScanState *) planstate)->trss_sinstrument;
 
-				/* collect prefetch statistics from the read stream */
-				stats = planstate->ss_currentScanDesc->rs_instrument->io;
-
 				/* get the sum of the counters set within each and every process */
 				if (sinstrument)
 				{
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index 3bb5b0d1cd2..9edd27da2e6 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -275,9 +275,9 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e)
 										e->pcxt);
 			break;
 		case T_TidRangeScanState:
-			if (planstate->plan->parallel_aware)
-				ExecTidRangeScanEstimate((TidRangeScanState *) planstate,
-										 e->pcxt);
+			/* even when not parallel-aware, for EXPLAIN ANALYZE */
+			ExecTidRangeScanEstimate((TidRangeScanState *) planstate,
+									 e->pcxt);
 			break;
 		case T_AppendState:
 			if (planstate->plan->parallel_aware)
@@ -507,9 +507,9 @@ ExecParallelInitializeDSM(PlanState *planstate,
 											 d->pcxt);
 			break;
 		case T_TidRangeScanState:
-			if (planstate->plan->parallel_aware)
-				ExecTidRangeScanInitializeDSM((TidRangeScanState *) planstate,
-											  d->pcxt);
+			/* even when not parallel-aware, for EXPLAIN ANALYZE */
+			ExecTidRangeScanInitializeDSM((TidRangeScanState *) planstate,
+										  d->pcxt);
 			break;
 		case T_AppendState:
 			if (planstate->plan->parallel_aware)
@@ -1392,9 +1392,9 @@ ExecParallelInitializeWorker(PlanState *planstate, ParallelWorkerContext *pwcxt)
 												pwcxt);
 			break;
 		case T_TidRangeScanState:
-			if (planstate->plan->parallel_aware)
-				ExecTidRangeScanInitializeWorker((TidRangeScanState *) planstate,
-												 pwcxt);
+			/* even when not parallel-aware, for EXPLAIN ANALYZE */
+			ExecTidRangeScanInitializeWorker((TidRangeScanState *) planstate,
+											 pwcxt);
 			break;
 		case T_AppendState:
 			if (planstate->plan->parallel_aware)
diff --git a/src/backend/executor/nodeTidrangescan.c b/src/backend/executor/nodeTidrangescan.c
index 9b6e2b91183..7126538addc 100644
--- a/src/backend/executor/nodeTidrangescan.c
+++ b/src/backend/executor/nodeTidrangescan.c
@@ -471,6 +471,14 @@ ExecTidRangeScanEstimate(TidRangeScanState *node, ParallelContext *pcxt)
 {
 	EState	   *estate = node->ss.ps.state;
 	Size		size;
+	bool		instrument = node->ss.ps.instrument != NULL;
+	bool		parallel_aware = node->ss.ps.plan->parallel_aware;
+
+	if (!instrument && !parallel_aware)
+	{
+		/* No DSM required by the scan */
+		return;
+	}
 
 	size = table_parallelscan_estimate(node->ss.ss_currentRelation,
 									   estate->es_snapshot);
@@ -480,7 +488,7 @@ ExecTidRangeScanEstimate(TidRangeScanState *node, ParallelContext *pcxt)
 	size = MAXALIGN(size);
 
 	/* account for instrumentation, if required */
-	if (node->ss.ps.instrument && pcxt->nworkers > 0)
+	if (instrument && pcxt->nworkers > 0)
 	{
 		size = add_size(size, offsetof(SharedTidRangeScanInstrumentation, sinstrument));
 		size = add_size(size, mul_size(pcxt->nworkers, sizeof(TidRangeScanInstrumentation)));
@@ -502,15 +510,16 @@ ExecTidRangeScanInitializeDSM(TidRangeScanState *node, ParallelContext *pcxt)
 	EState	   *estate = node->ss.ps.state;
 	ParallelTableScanDesc pscan;
 	SharedTidRangeScanInstrumentation *sinstrument = NULL;
+	bool		instrument = node->ss.ps.instrument != NULL;
+	bool		parallel_aware = node->ss.ps.plan->parallel_aware;
 	Size	size;
-	char   *ptr;
 	uint32	flags = SO_NONE;
 
-	if (ScanRelIsReadOnly(&node->ss))
-		flags |= SO_HINT_REL_READ_ONLY;
-
-	if (estate->es_instrument)
-		flags |= SO_SCAN_INSTRUMENT;
+	if (!instrument && !parallel_aware)
+	{
+		/* No DSM required by the scan */
+		return;
+	}
 
 	size = MAXALIGN(node->trss_pscanlen);
 	if (node->ss.ps.instrument && pcxt->nworkers > 0)
@@ -525,26 +534,41 @@ ExecTidRangeScanInitializeDSM(TidRangeScanState *node, ParallelContext *pcxt)
 								  pscan,
 								  estate->es_snapshot);
 	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, flags);
 
 	/* initialize the shared instrumentation (with correct alignment) */
-	ptr = (char *) pscan;
-	ptr += MAXALIGN(node->trss_pscanlen);
-	if (node->ss.ps.instrument && pcxt->nworkers > 0)
+	if (instrument && pcxt->nworkers > 0)
+	{
+		/* initialize the shared instrumentation (with correct alignment) */
+		char *ptr = (char *) pscan;
+
+		ptr += MAXALIGN(node->trss_pscanlen);
+
 		sinstrument = (SharedTidRangeScanInstrumentation *) ptr;
 
-	if (sinstrument)
-	{
 		sinstrument->num_workers = pcxt->nworkers;
 
 		/* ensure any unfilled slots will contain zeroes */
 		memset(sinstrument->sinstrument, 0,
 			   pcxt->nworkers * sizeof(TidRangeScanInstrumentation));
+
+		node->trss_sinstrument = sinstrument;
 	}
 
-	node->trss_sinstrument = sinstrument;
+	if (!parallel_aware)
+	{
+		/* Only here to set up worker node's shared instrumentation */
+		return;
+	}
+
+	if (ScanRelIsReadOnly(&node->ss))
+		flags |= SO_HINT_REL_READ_ONLY;
+
+	if (estate->es_instrument)
+		flags |= SO_SCAN_INSTRUMENT;
+
+	node->ss.ss_currentScanDesc =
+		table_beginscan_parallel_tidrange(node->ss.ss_currentRelation,
+										  pscan, flags);
 }
 
 /* ----------------------------------------------------------------
@@ -573,28 +597,46 @@ void
 ExecTidRangeScanInitializeWorker(TidRangeScanState *node,
 								 ParallelWorkerContext *pwcxt)
 {
-	EState	   *estate = node->ss.ps.state;
 	ParallelTableScanDesc pscan;
-	char	   *ptr;
+	EState	   *estate = node->ss.ps.state;
+	bool		instrument = node->ss.ps.instrument != NULL;
+	bool		parallel_aware = node->ss.ps.plan->parallel_aware;
 	uint32		flags = SO_NONE;
 
+	if (!instrument && !parallel_aware)
+	{
+		/* No DSM required by the scan */
+		return;
+	}
+
+	pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
+
+	/* set pointer to the shared instrumentation */
+	if (instrument)
+	{
+		/* set pointer to the shared instrumentation */
+		char *ptr = (char *) pscan;
+		ptr += MAXALIGN(pscan->phs_len);
+
+		node->trss_sinstrument = (SharedTidRangeScanInstrumentation *) ptr;
+	}
+
+	if (!parallel_aware)
+	{
+		/* Only here to set up worker node's SharedInfo */
+		return;
+	}
+
 	if (ScanRelIsReadOnly(&node->ss))
 		flags |= SO_HINT_REL_READ_ONLY;
 
 	if (estate->es_instrument)
 		flags |= SO_SCAN_INSTRUMENT;
 
-	pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
+	/* XXX only start the scan for parallel-aware ones */
 	node->ss.ss_currentScanDesc =
 		table_beginscan_parallel_tidrange(node->ss.ss_currentRelation,
 										  pscan, flags);
-
-	/* set pointer to the shared instrumentation */
-	ptr = (char *) pscan;
-	ptr += MAXALIGN(pscan->phs_len);
-
-	if (node->ss.ps.instrument)
-		node->trss_sinstrument = (SharedTidRangeScanInstrumentation *) ptr;
 }
 
 /* ----------------------------------------------------------------
-- 
2.53.0

