agora inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
601+ messages / 1 participants
[nested] [flat]

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by:
Discussion:
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--caEBMJLxMU8EntZL
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v1-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-03 13:04  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-03 13:04 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples().  This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6f9c9c72de5..353607954ad 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Int64GetDatum(lck_stats->wait_time);
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--NGLzJYdKKlS7EhhF
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v2-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread

* [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function
@ 2026-06-30 04:48  Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 601+ messages in thread

From: Bertrand Drouvot @ 2026-06-30 04:48 UTC (permalink / raw)

Extract the tuple-building logic from pg_stat_get_lock() into a new
static helper pg_stat_lock_build_tuples(). This is in preparation for
pg_stat_get_backend_lock() which will reuse the same helper, following
the pattern established by pg_stat_io_build_tuples() for IO stats and
pg_stat_wal_build_tuple() for WAL stats.

Author: Bertrand Drouvot <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Tristan Partin <[email protected]>
Reviewed-by: Tatsuya Kawata <[email protected]>
Reviewed-by: Rui Zhao <[email protected]>
Discussion: https://postgr.es/m/aiAzEY%2BcMQb/W8yu%40bdtpg
---
 src/backend/utils/adt/pgstatfuncs.c | 47 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 16 deletions(-)
 100.0% src/backend/utils/adt/

diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 0c59df17901..1f9165f1616 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1737,38 +1737,53 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 									wal_stats->stat_reset_timestamp));
 }
 
-Datum
-pg_stat_get_lock(PG_FUNCTION_ARGS)
+/*
+ * pg_stat_lock_build_tuples
+ *
+ * Helper routine for pg_stat_get_lock(), filling a result tuplestore with one
+ * tuple for each lock type.
+ */
+static void
+pg_stat_lock_build_tuples(ReturnSetInfo *rsinfo,
+						  PgStat_LockEntry *lock_stats,
+						  TimestampTz stat_reset_timestamp)
 {
 #define PG_STAT_LOCK_COLS	5
-	ReturnSetInfo *rsinfo;
-	PgStat_Lock *lock_stats;
-
-	InitMaterializedSRF(fcinfo, 0);
-	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	lock_stats = pgstat_fetch_stat_lock();
-
 	for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
 	{
-		const char *locktypename;
 		Datum		values[PG_STAT_LOCK_COLS] = {0};
 		bool		nulls[PG_STAT_LOCK_COLS] = {0};
-		PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
+		PgStat_LockEntry *lck_stats = &lock_stats[lcktype];
 		int			i = 0;
 
-		locktypename = LockTagTypeNames[lcktype];
-
-		values[i++] = CStringGetTextDatum(locktypename);
+		values[i++] = CStringGetTextDatum(LockTagTypeNames[lcktype]);
 		values[i++] = Int64GetDatum(lck_stats->waits);
 		values[i++] = Float8GetDatum(pg_stat_us_to_ms(lck_stats->wait_time));
 		values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
-		values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
+		if (stat_reset_timestamp != 0)
+			values[i] = TimestampTzGetDatum(stat_reset_timestamp);
+		else
+			nulls[i] = true;
 
 		Assert(i + 1 == PG_STAT_LOCK_COLS);
 
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
+}
+
+Datum
+pg_stat_get_lock(PG_FUNCTION_ARGS)
+{
+	ReturnSetInfo *rsinfo;
+	PgStat_Lock *lock_stats;
+
+	InitMaterializedSRF(fcinfo, 0);
+	rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	lock_stats = pgstat_fetch_stat_lock();
+
+	pg_stat_lock_build_tuples(rsinfo, lock_stats->stats,
+							  lock_stats->stat_reset_timestamp);
 
 	return (Datum) 0;
 }
-- 
2.34.1


--sSr8jD3wWqMF3Sck
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v3-0002-Add-per-backend-lock-statistics.patch"



^ permalink  raw  reply  [nested|flat] 601+ messages in thread


end of thread, other threads:[~2026-06-30 04:48 UTC | newest]

Thread overview: 601+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v2 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-03 13:04 [PATCH v1 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>
2026-06-30 04:48 [PATCH v3 1/2] Refactor pg_stat_get_lock() to use a helper function Bertrand Drouvot <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox