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