public inbox for [email protected]  
help / color / mirror / Atom feed
From: Chao Li <[email protected]>
To: PostgreSQL-development <[email protected]>
Subject: Fix pgstat_database.c to honor passed database OIDs
Date: Fri, 10 Apr 2026 13:53:15 +0800
Message-ID: <[email protected]> (raw)

Hi,

In pgstat_database.c, pgstat_report_connect(), pgstat_report_disconnect(), and pgstat_reset_database_timestamp() all take a dboid parameter, but currently ignore it and use MyDatabaseId instead. While that does not seem to break anything today, it at least hurts readability.

This patch changes those three functions to use the passed dboid.

For pgstat_report_connect() and pgstat_report_disconnect(), there is only one caller, and it passes MyDatabaseId, so this change should be safe.

For pgstat_reset_database_timestamp(), in most paths dboid is also just MyDatabaseId. However, there is one path where dboid can be InvalidOid:

1 - pg_stat_reset_single_table_counters may pass InvalidOid to pgstat_reset for a shared relation.
```
Datum
pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)
{
	Oid			taboid = PG_GETARG_OID(0);
	Oid			dboid = (IsSharedRelation(taboid) ? InvalidOid : MyDatabaseId);

	pgstat_reset(PGSTAT_KIND_RELATION, dboid, taboid);

	PG_RETURN_VOID();
}
```

2 - pgstat_reset only calls pgstat_reset_database_timestamp when kind_info->accessed_across_databases is false.
```
void
pgstat_reset(PgStat_Kind kind, Oid dboid, uint64 objid)
{
	const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
	TimestampTz ts = GetCurrentTimestamp();

	/* not needed atm, and doesn't make sense with the current signature */
	Assert(!pgstat_get_kind_info(kind)->fixed_amount);

	/* reset the "single counter" */
	pgstat_reset_entry(kind, dboid, objid, ts);

	if (!kind_info->accessed_across_databases)
		pgstat_reset_database_timestamp(dboid, ts);
}
```

3 - In this path, kind is PGSTAT_KIND_RELATION, and accessed_across_databases is false:
```
	[PGSTAT_KIND_RELATION] = {
		.name = "relation",

		.fixed_amount = false,
		.write_to_file = true,

		.shared_size = sizeof(PgStatShared_Relation),
		.shared_data_off = offsetof(PgStatShared_Relation, stats),
		.shared_data_len = sizeof(((PgStatShared_Relation *) 0)->stats),
		.pending_size = sizeof(PgStat_TableStatus),

		.flush_pending_cb = pgstat_relation_flush_cb,
		.delete_pending_cb = pgstat_relation_delete_pending_cb,
		.reset_timestamp_cb = pgstat_relation_reset_timestamp_cb,
	},
```

So in this case, pgstat_reset_database_timestamp() can receive InvalidOid as dboid. In the current code, because that function ignores dboid and uses MyDatabaseId, calling pg_stat_reset_single_table_counters() on a shared relation can incorrectly reset the current database's stat_reset_timestamp. That behavior seems unintended, so this patch makes pgstat_reset_database_timestamp() return immediately when dboid is InvalidOid.

Please see the attached patch. “Make check-world” passed from my side.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/






Attachments:

  [application/octet-stream] v1-0001-Fix-pgstat_database.c-to-honor-passed-database-OI.patch (2.1K, 2-v1-0001-Fix-pgstat_database.c-to-honor-passed-database-OI.patch)
  download | inline diff:
From 8e965bb55562a675d17e37de8b20fe17fe4ec452 Mon Sep 17 00:00:00 2001
From: "Chao Li (Evan)" <[email protected]>
Date: Fri, 10 Apr 2026 11:21:20 +0800
Subject: [PATCH v1] Fix pgstat_database.c to honor passed database OIDs

Several functions in pgstat_database.c take a database OID argument
but then ignore it and use MyDatabaseId instead. That is confusing,
and in pgstat_reset_database_timestamp() it is plainly wrong, because
the function's contract is to reset the timestamp for the specified
database.

Use the passed dboid in pgstat_report_connect(),
pgstat_report_disconnect(), and pgstat_reset_database_timestamp().

Also make pgstat_reset_database_timestamp() return immediately when
called with an invalid OID, avoiding an unnecessary stats lookup.

Author: Chao Li <[email protected]>
Reviewed-by:
Discussion: https://postgr.es/m/
---
 src/backend/utils/activity/pgstat_database.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/backend/utils/activity/pgstat_database.c b/src/backend/utils/activity/pgstat_database.c
index f1846d3236c..36a84d1f0a4 100644
--- a/src/backend/utils/activity/pgstat_database.c
+++ b/src/backend/utils/activity/pgstat_database.c
@@ -243,7 +243,7 @@ pgstat_report_connect(Oid dboid)
 
 	pgLastSessionReportTime = MyStartTimestamp;
 
-	dbentry = pgstat_prep_database_pending(MyDatabaseId);
+	dbentry = pgstat_prep_database_pending(dboid);
 	dbentry->sessions++;
 }
 
@@ -258,7 +258,7 @@ pgstat_report_disconnect(Oid dboid)
 	if (!pgstat_should_report_connstat())
 		return;
 
-	dbentry = pgstat_prep_database_pending(MyDatabaseId);
+	dbentry = pgstat_prep_database_pending(dboid);
 
 	switch (pgStatSessionEndCause)
 	{
@@ -419,7 +419,10 @@ pgstat_reset_database_timestamp(Oid dboid, TimestampTz ts)
 	PgStat_EntryRef *dbref;
 	PgStatShared_Database *dbentry;
 
-	dbref = pgstat_get_entry_ref_locked(PGSTAT_KIND_DATABASE, MyDatabaseId, InvalidOid,
+	if (!OidIsValid(dboid))
+		return;
+
+	dbref = pgstat_get_entry_ref_locked(PGSTAT_KIND_DATABASE, dboid, InvalidOid,
 										false);
 
 	dbentry = (PgStatShared_Database *) dbref->shared_stats;
-- 
2.50.1 (Apple Git-155)



view thread (7+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected]
  Subject: Re: Fix pgstat_database.c to honor passed database OIDs
  In-Reply-To: <[email protected]>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox