From ff5827d48fb1ec0fc3909afa4bc98cf6f3fe1357 Mon Sep 17 00:00:00 2001
From: Manu <manuelreyesbravo@gmail.com>
Date: Mon, 21 Sep 2026 20:53:25 -0300
Subject: [PATCH v1 2/5] Reset the index build progress counters for every
 index build

Index AMs report their subphase, tuple counts and scan block counts
whether or not index_build() was asked to report progress, but
index_build() only reset those counters when it was.  When one command
builds several indexes without progress for each of them, as REPACK and
VACUUM FULL do when rebuilding a table's indexes, or CREATE INDEX does for
the partitions of a partitioned table, each build started from the counts
left by the previous one: tuples_done could be above the new
tuples_total until the AM got to its first update.

Reset those counters in every build.  They are the parameters whose
numbers were chosen not to collide with those of the commands that build
indexes, so writing them under another command is fine.  The phase is
still only set when progress is reported, since REPACK uses that number
for index_rebuild_count.

Found with the PROGRESS_DEBUG tracing proposed in the same thread.

Oversight in caec9d9fadf, which made the whole reset conditional.
---
 src/backend/catalog/index.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 2a46cc4de19..09e716fadd2 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3175,24 +3175,33 @@ index_build(Relation heapRelation,
 	save_nestlevel = NewGUCNestLevel();
 	RestrictSearchPath();
 
-	/* Set up initial progress report status */
-	if (progress)
+	/*
+	 * Set up initial progress report status.
+	 *
+	 * Index AMs report their subphase, tuple and block counts whether or not
+	 * the caller asked for progress, so reset those in any case: otherwise
+	 * they would start from the values left by an earlier index build of the
+	 * same command.  Their parameter numbers are reserved so as not to
+	 * collide with those of the commands that build indexes.  The phase is
+	 * only set when progress is reported.
+	 */
 	{
 		const int	progress_index[] = {
-			PROGRESS_CREATEIDX_PHASE,
 			PROGRESS_CREATEIDX_SUBPHASE,
 			PROGRESS_CREATEIDX_TUPLES_DONE,
 			PROGRESS_CREATEIDX_TUPLES_TOTAL,
 			PROGRESS_SCAN_BLOCKS_DONE,
-			PROGRESS_SCAN_BLOCKS_TOTAL
+			PROGRESS_SCAN_BLOCKS_TOTAL,
+			PROGRESS_CREATEIDX_PHASE
 		};
 		const int64 progress_vals[] = {
-			PROGRESS_CREATEIDX_PHASE_BUILD,
 			PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE,
-			0, 0, 0, 0
+			0, 0, 0, 0,
+			PROGRESS_CREATEIDX_PHASE_BUILD
 		};
 
-		pgstat_progress_update_multi_param(6, progress_index, progress_vals);
+		pgstat_progress_update_multi_param(progress ? 6 : 5,
+										   progress_index, progress_vals);
 	}
 
 	/*
-- 
2.55.0

