v1-0001-Fix-transient-NULL-query_id-in-pg_stat_activity.patch

application/octet-stream

Filename: v1-0001-Fix-transient-NULL-query_id-in-pg_stat_activity.patch
Type: application/octet-stream
Part: 0
Message: Re: bug reapper: Empty query_id in pg_stat_activity
From 7cbcc4eb19958bef05d4a8ffae22221cf07813e9 Mon Sep 17 00:00:00 2001
From: Srinath Reddy Sadipiralla <srinath2133@gmail.com>
Date: Thu, 28 Aug 2025 17:37:23 +0530
Subject: [PATCH 1/1] Fix transient NULL query_id in pg_stat_activity

When compute_query_id = on, pg_stat_activity.query_id could sometimes
appear as NULL even for queries that did receive a query ID.  The cause
was a timing gap in exec_simple_query(): pgstat_report_query_id() resets
st_query_id to 0, and only later is the new query_id assigned.  A
concurrent backend inspecting pg_stat_activity during this window would
see 0, which is displayed as NULL.

To fix, track the previous st_query_id in prev_st_query_id before the
reset.  In pg_stat_get_activity(), if st_query_id is still 0 but query
ID computation is enabled, return prev_st_query_id instead of reporting
NULL.

This change avoids NULLs and makes query_id reporting in pg_stat_activity
consistent.  Queries that genuinely lack a query ID
(e.g. when compute_query_id = off) continue to show NULL.
---
 src/backend/utils/activity/backend_status.c | 2 ++
 src/backend/utils/adt/pgstatfuncs.c         | 8 +++++++-
 src/include/utils/backend_status.h          | 1 +
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index a290cc4c975..f290306457f 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -320,6 +320,7 @@ pgstat_bestart_initial(void)
 	lbeentry.st_state = STATE_STARTING;
 	lbeentry.st_progress_command = PROGRESS_COMMAND_INVALID;
 	lbeentry.st_progress_command_target = InvalidOid;
+	lbeentry.prev_st_query_id = INT64CONST(0);
 	lbeentry.st_query_id = INT64CONST(0);
 	lbeentry.st_plan_id = INT64CONST(0);
 
@@ -662,6 +663,7 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
 	 */
 	if (state == STATE_RUNNING)
 	{
+		beentry->prev_st_query_id = beentry->st_query_id;
 		beentry->st_query_id = INT64CONST(0);
 		beentry->st_plan_id = INT64CONST(0);
 	}
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index c756c2bebaa..726321e97b5 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -31,6 +31,7 @@
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/timestamp.h"
+#include "nodes/queryjumble.h"
 
 #define UINT32_ACCESS_ONCE(var)		 ((uint32)(*((volatile uint32 *)&(var))))
 
@@ -641,7 +642,12 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 													 * delegated */
 			}
 			if (beentry->st_query_id == INT64CONST(0))
-				nulls[30] = true;
+			{
+				if(!IsQueryIdEnabled())
+					nulls[30] = true;
+				else
+					values[30] = Int64GetDatum(beentry->prev_st_query_id);
+			}
 			else
 				values[30] = Int64GetDatum(beentry->st_query_id);
 		}
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 3016501ac05..efa9a67cbe2 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -170,6 +170,7 @@ typedef struct PgBackendStatus
 	int64		st_progress_param[PGSTAT_NUM_PROGRESS_PARAM];
 
 	/* query identifier, optionally computed using post_parse_analyze_hook */
+	int64		prev_st_query_id;
 	int64		st_query_id;
 
 	/* plan identifier, optionally computed using planner_hook */
-- 
2.43.0