>> I do think having the ability to look up a specific entry based on a
>> key (that is, hash_search instead of hash_seq_search) would be useful.
>
> That's a great idea, thanks! I'm going to try that and include it in
> the next version of the patch if I succeed.

Here is the second version of the patch, as promised. I used hash_search
in case all three key arguments are provided, the same way as it is done
in the entry_reset() function. The diff doesn't look very pleasant.
Basically I just moved the code that forms one tuple in a new
pg_stat_statements_handle_entry() function to use it in
pg_stat_statements_internal().

I also had a second thought about adding a new struct just to pass three
key arguments as one filter to the internal function. In the v2 patch I
just pass the arguments as they are. I'm not sure which option is better.
Anyway, it should be the same in both entry_reset() and
pg_stat_statements_internal(), so if you say adding struct pgssFilter
was a good idea, I'll rewrite the patch to use it in both
pg_stat_statements_internal() and entry_reset().

On Thu, Sep 18, 2025 at 6:33 PM Sami Imseih <[email protected]> wrote:
>
> Yes, but my point is, if someone repeatedly lookup up pg_stat_statements
> with filters, they will end up loading the query text multiple times.
>
> for example:
> ````
> select * from pg_stat_statements where query_id in (10000, 20000, 30000);
> ```
>
> will only load the query text once to retrieve these 3 query IDs.
>
> If I instead do this, with the proposed patch:
>
> ```
> select * from pg_stat_statements(true, queryid=>10000);
> select * from pg_stat_statements(true, queryid=>20000);
> select * from pg_stat_statements(true, queryid=>30000);
>
> or
> select * from pg_stat_activity a, pg_stat_statements(true, 
> queryid=>a.query_id);
>
> ```
> I will have to load the query text file into memory for every invocation of
> pg_stat_statements.
>

You are right. At some point, if information about multiple queries is
needed, a single select from pg_stat_statements followed by filtering
will be more efficient than calling pg_stat_statements with filters
multiple times. That's something that should be documented.

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/
From 95b3bcc2957ad04f2581051104f37323f7d10afe Mon Sep 17 00:00:00 2001
From: Karina Litskevich <[email protected]>
Date: Wed, 3 Sep 2025 11:44:26 +0300
Subject: [PATCH v2] pg_stat_statements: add ability to filter statistics while
 sacnning pgss_hash

Author: Aleksandra Bondar
Author: Karina Litskevich
---
 .../pg_stat_statements--1.12--1.13.sql        |   3 +
 .../pg_stat_statements/pg_stat_statements.c   | 504 ++++++++++--------
 2 files changed, 291 insertions(+), 216 deletions(-)

diff --git a/contrib/pg_stat_statements/pg_stat_statements--1.12--1.13.sql b/contrib/pg_stat_statements/pg_stat_statements--1.12--1.13.sql
index 2f0eaf14ec3..613835f8c99 100644
--- a/contrib/pg_stat_statements/pg_stat_statements--1.12--1.13.sql
+++ b/contrib/pg_stat_statements/pg_stat_statements--1.12--1.13.sql
@@ -13,6 +13,9 @@ DROP FUNCTION pg_stat_statements(boolean);
 
 /* Now redefine */
 CREATE FUNCTION pg_stat_statements(IN showtext boolean,
+    IN userid oid DEFAULT 0,
+    IN dbid oid DEFAULT 0,
+    IN queryid bigint DEFAULT 0,
     OUT userid oid,
     OUT dbid oid,
     OUT toplevel bool,
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 0bb0f933399..860a3b7c58e 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -362,7 +362,10 @@ static void pgss_store(const char *query, int64 queryId,
 					   PlannedStmtOrigin planOrigin);
 static void pg_stat_statements_internal(FunctionCallInfo fcinfo,
 										pgssVersion api_version,
-										bool showtext);
+										bool showtext,
+										Oid userid,
+										Oid dbid,
+										int64 queryid);
 static Size pgss_memsize(void);
 static pgssEntry *entry_alloc(pgssHashKey *key, Size query_offset, int query_len,
 							  int encoding, bool sticky);
@@ -1594,8 +1597,12 @@ Datum
 pg_stat_statements_1_13(PG_FUNCTION_ARGS)
 {
 	bool		showtext = PG_GETARG_BOOL(0);
+	Oid			userid = PG_GETARG_OID(1);
+	Oid			dbid = PG_GETARG_OID(2);
+	int64		queryid = PG_GETARG_INT64(3);
 
-	pg_stat_statements_internal(fcinfo, PGSS_V1_13, showtext);
+	pg_stat_statements_internal(fcinfo, PGSS_V1_13, showtext,
+								userid, dbid, queryid);
 
 	return (Datum) 0;
 }
@@ -1605,7 +1612,7 @@ pg_stat_statements_1_12(PG_FUNCTION_ARGS)
 {
 	bool		showtext = PG_GETARG_BOOL(0);
 
-	pg_stat_statements_internal(fcinfo, PGSS_V1_12, showtext);
+	pg_stat_statements_internal(fcinfo, PGSS_V1_12, showtext, 0, 0, 0);
 
 	return (Datum) 0;
 }
@@ -1615,7 +1622,7 @@ pg_stat_statements_1_11(PG_FUNCTION_ARGS)
 {
 	bool		showtext = PG_GETARG_BOOL(0);
 
-	pg_stat_statements_internal(fcinfo, PGSS_V1_11, showtext);
+	pg_stat_statements_internal(fcinfo, PGSS_V1_11, showtext, 0, 0, 0);
 
 	return (Datum) 0;
 }
@@ -1625,7 +1632,7 @@ pg_stat_statements_1_10(PG_FUNCTION_ARGS)
 {
 	bool		showtext = PG_GETARG_BOOL(0);
 
-	pg_stat_statements_internal(fcinfo, PGSS_V1_10, showtext);
+	pg_stat_statements_internal(fcinfo, PGSS_V1_10, showtext, 0, 0, 0);
 
 	return (Datum) 0;
 }
@@ -1635,7 +1642,7 @@ pg_stat_statements_1_9(PG_FUNCTION_ARGS)
 {
 	bool		showtext = PG_GETARG_BOOL(0);
 
-	pg_stat_statements_internal(fcinfo, PGSS_V1_9, showtext);
+	pg_stat_statements_internal(fcinfo, PGSS_V1_9, showtext, 0, 0, 0);
 
 	return (Datum) 0;
 }
@@ -1645,7 +1652,7 @@ pg_stat_statements_1_8(PG_FUNCTION_ARGS)
 {
 	bool		showtext = PG_GETARG_BOOL(0);
 
-	pg_stat_statements_internal(fcinfo, PGSS_V1_8, showtext);
+	pg_stat_statements_internal(fcinfo, PGSS_V1_8, showtext, 0, 0, 0);
 
 	return (Datum) 0;
 }
@@ -1655,7 +1662,7 @@ pg_stat_statements_1_3(PG_FUNCTION_ARGS)
 {
 	bool		showtext = PG_GETARG_BOOL(0);
 
-	pg_stat_statements_internal(fcinfo, PGSS_V1_3, showtext);
+	pg_stat_statements_internal(fcinfo, PGSS_V1_3, showtext, 0, 0, 0);
 
 	return (Datum) 0;
 }
@@ -1665,7 +1672,7 @@ pg_stat_statements_1_2(PG_FUNCTION_ARGS)
 {
 	bool		showtext = PG_GETARG_BOOL(0);
 
-	pg_stat_statements_internal(fcinfo, PGSS_V1_2, showtext);
+	pg_stat_statements_internal(fcinfo, PGSS_V1_2, showtext, 0, 0, 0);
 
 	return (Datum) 0;
 }
@@ -1678,19 +1685,243 @@ Datum
 pg_stat_statements(PG_FUNCTION_ARGS)
 {
 	/* If it's really API 1.1, we'll figure that out below */
-	pg_stat_statements_internal(fcinfo, PGSS_V1_0, true);
+	pg_stat_statements_internal(fcinfo, PGSS_V1_0, true, 0, 0, 0);
 
 	return (Datum) 0;
 }
 
+static void
+pg_stat_statements_handle_entry(const ReturnSetInfo *rsinfo,
+								pgssEntry *entry,
+								bool showtext,
+								bool is_allowed_role,
+								Oid userid,
+								char *qbuffer,
+								Size qbuffer_size,
+								pgssVersion api_version)
+{
+	Datum		values[PG_STAT_STATEMENTS_COLS];
+	bool		nulls[PG_STAT_STATEMENTS_COLS];
+	int			i = 0;
+	Counters	tmp;
+	double		stddev;
+	int64		queryid = entry->key.queryid;
+	TimestampTz stats_since;
+	TimestampTz minmax_stats_since;
+
+	memset(values, 0, sizeof(values));
+	memset(nulls, 0, sizeof(nulls));
+
+	values[i++] = ObjectIdGetDatum(entry->key.userid);
+	values[i++] = ObjectIdGetDatum(entry->key.dbid);
+	if (api_version >= PGSS_V1_9)
+		values[i++] = BoolGetDatum(entry->key.toplevel);
+
+	if (is_allowed_role || entry->key.userid == userid)
+	{
+		if (api_version >= PGSS_V1_2)
+			values[i++] = Int64GetDatumFast(queryid);
+
+		if (showtext)
+		{
+			char	   *qstr = qtext_fetch(entry->query_offset,
+										   entry->query_len,
+										   qbuffer,
+										   qbuffer_size);
+
+			if (qstr)
+			{
+				char	   *enc;
+
+				enc = pg_any_to_server(qstr,
+									   entry->query_len,
+									   entry->encoding);
+
+				values[i++] = CStringGetTextDatum(enc);
+
+				if (enc != qstr)
+					pfree(enc);
+			}
+			else
+			{
+				/* Just return a null if we fail to find the text */
+				nulls[i++] = true;
+			}
+		}
+		else
+		{
+			/* Query text not requested */
+			nulls[i++] = true;
+		}
+	}
+	else
+	{
+		/* Don't show queryid */
+		if (api_version >= PGSS_V1_2)
+			nulls[i++] = true;
+
+		/*
+		 * Don't show query text, but hint as to the reason for not doing
+		 * so if it was requested
+		 */
+		if (showtext)
+			values[i++] = CStringGetTextDatum("<insufficient privilege>");
+		else
+			nulls[i++] = true;
+	}
+
+	/* copy counters to a local variable to keep locking time short */
+	SpinLockAcquire(&entry->mutex);
+	tmp = entry->counters;
+	SpinLockRelease(&entry->mutex);
+
+	/*
+	 * The spinlock is not required when reading these two as they are
+	 * always updated when holding pgss->lock exclusively.
+	 */
+	stats_since = entry->stats_since;
+	minmax_stats_since = entry->minmax_stats_since;
+
+	/* Skip entry if unexecuted (ie, it's a pending "sticky" entry) */
+	if (IS_STICKY(tmp))
+		return;
+
+	/* Note that we rely on PGSS_PLAN being 0 and PGSS_EXEC being 1. */
+	for (int kind = 0; kind < PGSS_NUMKIND; kind++)
+	{
+		if (kind == PGSS_EXEC || api_version >= PGSS_V1_8)
+		{
+			values[i++] = Int64GetDatumFast(tmp.calls[kind]);
+			values[i++] = Float8GetDatumFast(tmp.total_time[kind]);
+		}
+
+		if ((kind == PGSS_EXEC && api_version >= PGSS_V1_3) ||
+			api_version >= PGSS_V1_8)
+		{
+			values[i++] = Float8GetDatumFast(tmp.min_time[kind]);
+			values[i++] = Float8GetDatumFast(tmp.max_time[kind]);
+			values[i++] = Float8GetDatumFast(tmp.mean_time[kind]);
+
+			/*
+			 * Note we are calculating the population variance here, not
+			 * the sample variance, as we have data for the whole
+			 * population, so Bessel's correction is not used, and we
+			 * don't divide by tmp.calls - 1.
+			 */
+			if (tmp.calls[kind] > 1)
+				stddev = sqrt(tmp.sum_var_time[kind] / tmp.calls[kind]);
+			else
+				stddev = 0.0;
+			values[i++] = Float8GetDatumFast(stddev);
+		}
+	}
+	values[i++] = Int64GetDatumFast(tmp.rows);
+	values[i++] = Int64GetDatumFast(tmp.shared_blks_hit);
+	values[i++] = Int64GetDatumFast(tmp.shared_blks_read);
+	if (api_version >= PGSS_V1_1)
+		values[i++] = Int64GetDatumFast(tmp.shared_blks_dirtied);
+	values[i++] = Int64GetDatumFast(tmp.shared_blks_written);
+	values[i++] = Int64GetDatumFast(tmp.local_blks_hit);
+	values[i++] = Int64GetDatumFast(tmp.local_blks_read);
+	if (api_version >= PGSS_V1_1)
+		values[i++] = Int64GetDatumFast(tmp.local_blks_dirtied);
+	values[i++] = Int64GetDatumFast(tmp.local_blks_written);
+	values[i++] = Int64GetDatumFast(tmp.temp_blks_read);
+	values[i++] = Int64GetDatumFast(tmp.temp_blks_written);
+	if (api_version >= PGSS_V1_1)
+	{
+		values[i++] = Float8GetDatumFast(tmp.shared_blk_read_time);
+		values[i++] = Float8GetDatumFast(tmp.shared_blk_write_time);
+	}
+	if (api_version >= PGSS_V1_11)
+	{
+		values[i++] = Float8GetDatumFast(tmp.local_blk_read_time);
+		values[i++] = Float8GetDatumFast(tmp.local_blk_write_time);
+	}
+	if (api_version >= PGSS_V1_10)
+	{
+		values[i++] = Float8GetDatumFast(tmp.temp_blk_read_time);
+		values[i++] = Float8GetDatumFast(tmp.temp_blk_write_time);
+	}
+	if (api_version >= PGSS_V1_8)
+	{
+		char		buf[256];
+		Datum		wal_bytes;
+
+		values[i++] = Int64GetDatumFast(tmp.wal_records);
+		values[i++] = Int64GetDatumFast(tmp.wal_fpi);
+
+		snprintf(buf, sizeof buf, UINT64_FORMAT, tmp.wal_bytes);
+
+		/* Convert to numeric. */
+		wal_bytes = DirectFunctionCall3(numeric_in,
+										CStringGetDatum(buf),
+										ObjectIdGetDatum(0),
+										Int32GetDatum(-1));
+		values[i++] = wal_bytes;
+	}
+	if (api_version >= PGSS_V1_12)
+	{
+		values[i++] = Int64GetDatumFast(tmp.wal_buffers_full);
+	}
+	if (api_version >= PGSS_V1_10)
+	{
+		values[i++] = Int64GetDatumFast(tmp.jit_functions);
+		values[i++] = Float8GetDatumFast(tmp.jit_generation_time);
+		values[i++] = Int64GetDatumFast(tmp.jit_inlining_count);
+		values[i++] = Float8GetDatumFast(tmp.jit_inlining_time);
+		values[i++] = Int64GetDatumFast(tmp.jit_optimization_count);
+		values[i++] = Float8GetDatumFast(tmp.jit_optimization_time);
+		values[i++] = Int64GetDatumFast(tmp.jit_emission_count);
+		values[i++] = Float8GetDatumFast(tmp.jit_emission_time);
+	}
+	if (api_version >= PGSS_V1_11)
+	{
+		values[i++] = Int64GetDatumFast(tmp.jit_deform_count);
+		values[i++] = Float8GetDatumFast(tmp.jit_deform_time);
+	}
+	if (api_version >= PGSS_V1_12)
+	{
+		values[i++] = Int64GetDatumFast(tmp.parallel_workers_to_launch);
+		values[i++] = Int64GetDatumFast(tmp.parallel_workers_launched);
+	}
+	if (api_version >= PGSS_V1_13)
+	{
+		values[i++] = Int64GetDatumFast(tmp.generic_plan_calls);
+		values[i++] = Int64GetDatumFast(tmp.custom_plan_calls);
+	}
+	if (api_version >= PGSS_V1_11)
+	{
+		values[i++] = TimestampTzGetDatum(stats_since);
+		values[i++] = TimestampTzGetDatum(minmax_stats_since);
+	}
+
+	Assert(i == (api_version == PGSS_V1_0 ? PG_STAT_STATEMENTS_COLS_V1_0 :
+				 api_version == PGSS_V1_1 ? PG_STAT_STATEMENTS_COLS_V1_1 :
+				 api_version == PGSS_V1_2 ? PG_STAT_STATEMENTS_COLS_V1_2 :
+				 api_version == PGSS_V1_3 ? PG_STAT_STATEMENTS_COLS_V1_3 :
+				 api_version == PGSS_V1_8 ? PG_STAT_STATEMENTS_COLS_V1_8 :
+				 api_version == PGSS_V1_9 ? PG_STAT_STATEMENTS_COLS_V1_9 :
+				 api_version == PGSS_V1_10 ? PG_STAT_STATEMENTS_COLS_V1_10 :
+				 api_version == PGSS_V1_11 ? PG_STAT_STATEMENTS_COLS_V1_11 :
+				 api_version == PGSS_V1_12 ? PG_STAT_STATEMENTS_COLS_V1_12 :
+				 api_version == PGSS_V1_13 ? PG_STAT_STATEMENTS_COLS_V1_13 :
+				 -1 /* fail if you forget to update this assert */ ));
+
+	tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
+}
+
 /* Common code for all versions of pg_stat_statements() */
 static void
 pg_stat_statements_internal(FunctionCallInfo fcinfo,
 							pgssVersion api_version,
-							bool showtext)
+							bool showtext,
+							Oid userid,
+							Oid dbid,
+							int64 queryid)
 {
 	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-	Oid			userid = GetUserId();
+	Oid			current_userid = GetUserId();
 	bool		is_allowed_role = false;
 	char	   *qbuffer = NULL;
 	Size		qbuffer_size = 0;
@@ -1703,7 +1934,7 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
 	 * Superusers or roles with the privileges of pg_read_all_stats members
 	 * are allowed
 	 */
-	is_allowed_role = has_privs_of_role(userid, ROLE_PG_READ_ALL_STATS);
+	is_allowed_role = has_privs_of_role(current_userid, ROLE_PG_READ_ALL_STATS);
 
 	/* hash table must exist already */
 	if (!pgss || !pgss_hash)
@@ -1826,218 +2057,59 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
 		}
 	}
 
-	hash_seq_init(&hash_seq, pgss_hash);
-	while ((entry = hash_seq_search(&hash_seq)) != NULL)
+	if (userid != 0 && dbid != 0 && queryid != INT64CONST(0))
 	{
-		Datum		values[PG_STAT_STATEMENTS_COLS];
-		bool		nulls[PG_STAT_STATEMENTS_COLS];
-		int			i = 0;
-		Counters	tmp;
-		double		stddev;
-		int64		queryid = entry->key.queryid;
-		TimestampTz stats_since;
-		TimestampTz minmax_stats_since;
-
-		memset(values, 0, sizeof(values));
-		memset(nulls, 0, sizeof(nulls));
-
-		values[i++] = ObjectIdGetDatum(entry->key.userid);
-		values[i++] = ObjectIdGetDatum(entry->key.dbid);
-		if (api_version >= PGSS_V1_9)
-			values[i++] = BoolGetDatum(entry->key.toplevel);
-
-		if (is_allowed_role || entry->key.userid == userid)
-		{
-			if (api_version >= PGSS_V1_2)
-				values[i++] = Int64GetDatumFast(queryid);
-
-			if (showtext)
-			{
-				char	   *qstr = qtext_fetch(entry->query_offset,
-											   entry->query_len,
-											   qbuffer,
-											   qbuffer_size);
-
-				if (qstr)
-				{
-					char	   *enc;
-
-					enc = pg_any_to_server(qstr,
-										   entry->query_len,
-										   entry->encoding);
-
-					values[i++] = CStringGetTextDatum(enc);
-
-					if (enc != qstr)
-						pfree(enc);
-				}
-				else
-				{
-					/* Just return a null if we fail to find the text */
-					nulls[i++] = true;
-				}
-			}
-			else
-			{
-				/* Query text not requested */
-				nulls[i++] = true;
-			}
-		}
-		else
-		{
-			/* Don't show queryid */
-			if (api_version >= PGSS_V1_2)
-				nulls[i++] = true;
-
-			/*
-			 * Don't show query text, but hint as to the reason for not doing
-			 * so if it was requested
-			 */
-			if (showtext)
-				values[i++] = CStringGetTextDatum("<insufficient privilege>");
-			else
-				nulls[i++] = true;
-		}
+		/* If all the parameters are available, use the fast path. */
+		pgssHashKey key;
+		memset(&key, 0, sizeof(pgssHashKey));
+		key.userid = userid;
+		key.dbid = dbid;
+		key.queryid = queryid;
 
-		/* copy counters to a local variable to keep locking time short */
-		SpinLockAcquire(&entry->mutex);
-		tmp = entry->counters;
-		SpinLockRelease(&entry->mutex);
+		/* Find the non-top-level entry. */
+		key.toplevel = false;
+		entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
 
-		/*
-		 * The spinlock is not required when reading these two as they are
-		 * always updated when holding pgss->lock exclusively.
-		 */
-		stats_since = entry->stats_since;
-		minmax_stats_since = entry->minmax_stats_since;
+		if (entry)
+			pg_stat_statements_handle_entry(rsinfo, entry, showtext,
+											is_allowed_role, current_userid,
+											qbuffer, qbuffer_size,
+											api_version);
 
-		/* Skip entry if unexecuted (ie, it's a pending "sticky" entry) */
-		if (IS_STICKY(tmp))
-			continue;
+		/* Also find the top-level entry. */
+		key.toplevel = true;
+		entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
 
-		/* Note that we rely on PGSS_PLAN being 0 and PGSS_EXEC being 1. */
-		for (int kind = 0; kind < PGSS_NUMKIND; kind++)
+		if (entry)
+			pg_stat_statements_handle_entry(rsinfo, entry, showtext,
+											is_allowed_role, current_userid,
+											qbuffer, qbuffer_size,
+											api_version);
+	}
+	else if (userid != 0 || dbid != 0 || queryid != INT64CONST(0))
+	{
+		hash_seq_init(&hash_seq, pgss_hash);
+		while ((entry = hash_seq_search(&hash_seq)) != NULL)
 		{
-			if (kind == PGSS_EXEC || api_version >= PGSS_V1_8)
-			{
-				values[i++] = Int64GetDatumFast(tmp.calls[kind]);
-				values[i++] = Float8GetDatumFast(tmp.total_time[kind]);
-			}
-
-			if ((kind == PGSS_EXEC && api_version >= PGSS_V1_3) ||
-				api_version >= PGSS_V1_8)
+			if ((!userid || entry->key.userid == userid) &&
+				(!dbid || entry->key.dbid == dbid) &&
+				(!queryid || entry->key.queryid == queryid))
 			{
-				values[i++] = Float8GetDatumFast(tmp.min_time[kind]);
-				values[i++] = Float8GetDatumFast(tmp.max_time[kind]);
-				values[i++] = Float8GetDatumFast(tmp.mean_time[kind]);
-
-				/*
-				 * Note we are calculating the population variance here, not
-				 * the sample variance, as we have data for the whole
-				 * population, so Bessel's correction is not used, and we
-				 * don't divide by tmp.calls - 1.
-				 */
-				if (tmp.calls[kind] > 1)
-					stddev = sqrt(tmp.sum_var_time[kind] / tmp.calls[kind]);
-				else
-					stddev = 0.0;
-				values[i++] = Float8GetDatumFast(stddev);
+				pg_stat_statements_handle_entry(rsinfo, entry, showtext,
+												is_allowed_role, current_userid,
+												qbuffer, qbuffer_size,
+												api_version);
 			}
 		}
-		values[i++] = Int64GetDatumFast(tmp.rows);
-		values[i++] = Int64GetDatumFast(tmp.shared_blks_hit);
-		values[i++] = Int64GetDatumFast(tmp.shared_blks_read);
-		if (api_version >= PGSS_V1_1)
-			values[i++] = Int64GetDatumFast(tmp.shared_blks_dirtied);
-		values[i++] = Int64GetDatumFast(tmp.shared_blks_written);
-		values[i++] = Int64GetDatumFast(tmp.local_blks_hit);
-		values[i++] = Int64GetDatumFast(tmp.local_blks_read);
-		if (api_version >= PGSS_V1_1)
-			values[i++] = Int64GetDatumFast(tmp.local_blks_dirtied);
-		values[i++] = Int64GetDatumFast(tmp.local_blks_written);
-		values[i++] = Int64GetDatumFast(tmp.temp_blks_read);
-		values[i++] = Int64GetDatumFast(tmp.temp_blks_written);
-		if (api_version >= PGSS_V1_1)
-		{
-			values[i++] = Float8GetDatumFast(tmp.shared_blk_read_time);
-			values[i++] = Float8GetDatumFast(tmp.shared_blk_write_time);
-		}
-		if (api_version >= PGSS_V1_11)
-		{
-			values[i++] = Float8GetDatumFast(tmp.local_blk_read_time);
-			values[i++] = Float8GetDatumFast(tmp.local_blk_write_time);
-		}
-		if (api_version >= PGSS_V1_10)
-		{
-			values[i++] = Float8GetDatumFast(tmp.temp_blk_read_time);
-			values[i++] = Float8GetDatumFast(tmp.temp_blk_write_time);
-		}
-		if (api_version >= PGSS_V1_8)
-		{
-			char		buf[256];
-			Datum		wal_bytes;
-
-			values[i++] = Int64GetDatumFast(tmp.wal_records);
-			values[i++] = Int64GetDatumFast(tmp.wal_fpi);
-
-			snprintf(buf, sizeof buf, UINT64_FORMAT, tmp.wal_bytes);
-
-			/* Convert to numeric. */
-			wal_bytes = DirectFunctionCall3(numeric_in,
-											CStringGetDatum(buf),
-											ObjectIdGetDatum(0),
-											Int32GetDatum(-1));
-			values[i++] = wal_bytes;
-		}
-		if (api_version >= PGSS_V1_12)
-		{
-			values[i++] = Int64GetDatumFast(tmp.wal_buffers_full);
-		}
-		if (api_version >= PGSS_V1_10)
-		{
-			values[i++] = Int64GetDatumFast(tmp.jit_functions);
-			values[i++] = Float8GetDatumFast(tmp.jit_generation_time);
-			values[i++] = Int64GetDatumFast(tmp.jit_inlining_count);
-			values[i++] = Float8GetDatumFast(tmp.jit_inlining_time);
-			values[i++] = Int64GetDatumFast(tmp.jit_optimization_count);
-			values[i++] = Float8GetDatumFast(tmp.jit_optimization_time);
-			values[i++] = Int64GetDatumFast(tmp.jit_emission_count);
-			values[i++] = Float8GetDatumFast(tmp.jit_emission_time);
-		}
-		if (api_version >= PGSS_V1_11)
-		{
-			values[i++] = Int64GetDatumFast(tmp.jit_deform_count);
-			values[i++] = Float8GetDatumFast(tmp.jit_deform_time);
-		}
-		if (api_version >= PGSS_V1_12)
-		{
-			values[i++] = Int64GetDatumFast(tmp.parallel_workers_to_launch);
-			values[i++] = Int64GetDatumFast(tmp.parallel_workers_launched);
-		}
-		if (api_version >= PGSS_V1_13)
-		{
-			values[i++] = Int64GetDatumFast(tmp.generic_plan_calls);
-			values[i++] = Int64GetDatumFast(tmp.custom_plan_calls);
-		}
-		if (api_version >= PGSS_V1_11)
-		{
-			values[i++] = TimestampTzGetDatum(stats_since);
-			values[i++] = TimestampTzGetDatum(minmax_stats_since);
-		}
-
-		Assert(i == (api_version == PGSS_V1_0 ? PG_STAT_STATEMENTS_COLS_V1_0 :
-					 api_version == PGSS_V1_1 ? PG_STAT_STATEMENTS_COLS_V1_1 :
-					 api_version == PGSS_V1_2 ? PG_STAT_STATEMENTS_COLS_V1_2 :
-					 api_version == PGSS_V1_3 ? PG_STAT_STATEMENTS_COLS_V1_3 :
-					 api_version == PGSS_V1_8 ? PG_STAT_STATEMENTS_COLS_V1_8 :
-					 api_version == PGSS_V1_9 ? PG_STAT_STATEMENTS_COLS_V1_9 :
-					 api_version == PGSS_V1_10 ? PG_STAT_STATEMENTS_COLS_V1_10 :
-					 api_version == PGSS_V1_11 ? PG_STAT_STATEMENTS_COLS_V1_11 :
-					 api_version == PGSS_V1_12 ? PG_STAT_STATEMENTS_COLS_V1_12 :
-					 api_version == PGSS_V1_13 ? PG_STAT_STATEMENTS_COLS_V1_13 :
-					 -1 /* fail if you forget to update this assert */ ));
-
-		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
+	}
+	else
+	{
+		hash_seq_init(&hash_seq, pgss_hash);
+		while ((entry = hash_seq_search(&hash_seq)) != NULL)
+			pg_stat_statements_handle_entry(rsinfo, entry, showtext,
+											is_allowed_role, current_userid,
+											qbuffer, qbuffer_size,
+											api_version);
 	}
 
 	LWLockRelease(pgss->lock);
-- 
2.34.1

Reply via email to