Subject: pg_stat_statements: more test coverage

From: Peter Eisentraut <[email-masked]>
Date: Sat, 23 Dec 2023 15:18:01 +0100

pg_stat_statements has some significant gaps in test coverage, 
especially around the serialization of data around server restarts, so I 
wrote a test for that and also made some other smaller tweaks to 
increase the coverage a bit.  These patches are all independent of each 
other.

After that, the only major function that isn't tested is gc_qtexts(). 
Maybe a future project.

From 32b51698b581b816f7ca2ff16c92be8d25e7fd66 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email-masked]>
Date: Sat, 23 Dec 2023 14:25:26 +0100
Subject: [PATCH v1 1/5] pg_stat_statements: Exclude from lcov functions that
 are impossible to test

The current code only supports installing version 1.4 of
pg_stat_statements and upgrading from there.  So the C code entry
points for older versions are not reachable from the tests.  To
prevent this from ruining the test coverage figures, mark those
functions are excluded from lcov.
---
 contrib/pg_stat_statements/pg_stat_statements.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 6f62a531f7..8ac73bf55e 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -311,13 +311,15 @@ static bool pgss_save = true;	/* whether to save stats across shutdown */
 PG_FUNCTION_INFO_V1(pg_stat_statements_reset);
 PG_FUNCTION_INFO_V1(pg_stat_statements_reset_1_7);
 PG_FUNCTION_INFO_V1(pg_stat_statements_reset_1_11);
+/* LCOV_EXCL_START */
+PG_FUNCTION_INFO_V1(pg_stat_statements);
 PG_FUNCTION_INFO_V1(pg_stat_statements_1_2);
+/* LCOV_EXCL_STOP */
 PG_FUNCTION_INFO_V1(pg_stat_statements_1_3);
 PG_FUNCTION_INFO_V1(pg_stat_statements_1_8);
 PG_FUNCTION_INFO_V1(pg_stat_statements_1_9);
 PG_FUNCTION_INFO_V1(pg_stat_statements_1_10);
 PG_FUNCTION_INFO_V1(pg_stat_statements_1_11);
-PG_FUNCTION_INFO_V1(pg_stat_statements);
 PG_FUNCTION_INFO_V1(pg_stat_statements_info);
 
 static void pgss_shmem_request(void);
@@ -1610,6 +1612,8 @@ pg_stat_statements_1_3(PG_FUNCTION_ARGS)
 	return (Datum) 0;
 }
 
+/* LCOV_EXCL_START */
+
 Datum
 pg_stat_statements_1_2(PG_FUNCTION_ARGS)
 {
@@ -1633,6 +1637,8 @@ pg_stat_statements(PG_FUNCTION_ARGS)
 	return (Datum) 0;
 }
 
+/* LCOV_EXCL_STOP */
+
 /* Common code for all versions of pg_stat_statements() */
 static void
 pg_stat_statements_internal(FunctionCallInfo fcinfo,

base-commit: 3e2e0d5ad7fcb89d18a71cbfc885ef184e1b6f2e
-- 
2.43.0

From 1033183cea71c6bd37934cedb972d35a4e251134 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email-masked]>
Date: Sat, 23 Dec 2023 14:25:26 +0100
Subject: [PATCH v1 2/5] pg_stat_statements: Add coverage for
 pg_stat_statements_1_8()

This requires reading pg_stat_statements at least once while the 1.8
version of the extension is installed.
---
 .../expected/oldextversions.out               | 24 ++++++++++++-------
 .../pg_stat_statements/sql/oldextversions.sql |  3 ++-
 2 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/contrib/pg_stat_statements/expected/oldextversions.out b/contrib/pg_stat_statements/expected/oldextversions.out
index ec317b0d6b..f3a90cac0a 100644
--- a/contrib/pg_stat_statements/expected/oldextversions.out
+++ b/contrib/pg_stat_statements/expected/oldextversions.out
@@ -88,6 +88,17 @@ SELECT count(*) > 0 AS has_data FROM pg_stat_statements;
 
 -- New functions and views for pg_stat_statements in 1.8
 AlTER EXTENSION pg_stat_statements UPDATE TO '1.8';
+SELECT pg_get_functiondef('pg_stat_statements_reset'::regproc);
+                                                       pg_get_functiondef                                                       
+--------------------------------------------------------------------------------------------------------------------------------
+ CREATE OR REPLACE FUNCTION public.pg_stat_statements_reset(userid oid DEFAULT 0, dbid oid DEFAULT 0, queryid bigint DEFAULT 0)+
+  RETURNS void                                                                                                                 +
+  LANGUAGE c                                                                                                                   +
+  PARALLEL SAFE STRICT                                                                                                         +
+ AS '$libdir/pg_stat_statements', $function$pg_stat_statements_reset_1_7$function$                                             +
+ 
+(1 row)
+
 \d pg_stat_statements
                     View "public.pg_stat_statements"
        Column        |       Type       | Collation | Nullable | Default 
@@ -125,15 +136,10 @@ AlTER EXTENSION pg_stat_statements UPDATE TO '1.8';
  wal_fpi             | bigint           |           |          | 
  wal_bytes           | numeric          |           |          | 
 
-SELECT pg_get_functiondef('pg_stat_statements_reset'::regproc);
-                                                       pg_get_functiondef                                                       
---------------------------------------------------------------------------------------------------------------------------------
- CREATE OR REPLACE FUNCTION public.pg_stat_statements_reset(userid oid DEFAULT 0, dbid oid DEFAULT 0, queryid bigint DEFAULT 0)+
-  RETURNS void                                                                                                                 +
-  LANGUAGE c                                                                                                                   +
-  PARALLEL SAFE STRICT                                                                                                         +
- AS '$libdir/pg_stat_statements', $function$pg_stat_statements_reset_1_7$function$                                             +
- 
+SELECT count(*) > 0 AS has_data FROM pg_stat_statements;
+ has_data 
+----------
+ t
 (1 row)
 
 -- New function pg_stat_statement_info, and new function
diff --git a/contrib/pg_stat_statements/sql/oldextversions.sql b/contrib/pg_stat_statements/sql/oldextversions.sql
index ec06caa5dd..5cf515f6b0 100644
--- a/contrib/pg_stat_statements/sql/oldextversions.sql
+++ b/contrib/pg_stat_statements/sql/oldextversions.sql
@@ -33,8 +33,9 @@ CREATE EXTENSION pg_stat_statements WITH VERSION '1.4';
 
 -- New functions and views for pg_stat_statements in 1.8
 AlTER EXTENSION pg_stat_statements UPDATE TO '1.8';
-\d pg_stat_statements
 SELECT pg_get_functiondef('pg_stat_statements_reset'::regproc);
+\d pg_stat_statements
+SELECT count(*) > 0 AS has_data FROM pg_stat_statements;
 
 -- New function pg_stat_statement_info, and new function
 -- and view for pg_stat_statements introduced in 1.9
-- 
2.43.0

From 154485f21bd5e826646874c5febc6c4fea68a1b8 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email-masked]>
Date: Sat, 23 Dec 2023 14:25:26 +0100
Subject: [PATCH v1 3/5] pg_stat_statements: Add coverage for
 pg_stat_statements_reset_1_7

Run pg_stat_statements_reset() once while the appropriate extension
version is installed.
---
 .../pg_stat_statements/expected/oldextversions.out   | 12 ++++++++++++
 contrib/pg_stat_statements/sql/oldextversions.sql    |  2 ++
 2 files changed, 14 insertions(+)

diff --git a/contrib/pg_stat_statements/expected/oldextversions.out b/contrib/pg_stat_statements/expected/oldextversions.out
index f3a90cac0a..5842c930e5 100644
--- a/contrib/pg_stat_statements/expected/oldextversions.out
+++ b/contrib/pg_stat_statements/expected/oldextversions.out
@@ -52,6 +52,12 @@ SELECT pg_get_functiondef('pg_stat_statements_reset'::regproc);
  
 (1 row)
 
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset 
+--------------------------
+ 
+(1 row)
+
 \d pg_stat_statements
                     View "public.pg_stat_statements"
        Column        |       Type       | Collation | Nullable | Default 
@@ -330,4 +336,10 @@ SELECT pg_get_functiondef('pg_stat_statements_reset'::regproc);
  
 (1 row)
 
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+ t 
+---
+ t
+(1 row)
+
 DROP EXTENSION pg_stat_statements;
diff --git a/contrib/pg_stat_statements/sql/oldextversions.sql b/contrib/pg_stat_statements/sql/oldextversions.sql
index 5cf515f6b0..38d5505d0d 100644
--- a/contrib/pg_stat_statements/sql/oldextversions.sql
+++ b/contrib/pg_stat_statements/sql/oldextversions.sql
@@ -28,6 +28,7 @@ CREATE EXTENSION pg_stat_statements WITH VERSION '1.4';
 SELECT pg_stat_statements_reset();
 RESET SESSION AUTHORIZATION;
 SELECT pg_get_functiondef('pg_stat_statements_reset'::regproc);
+SELECT pg_stat_statements_reset();
 \d pg_stat_statements
 SELECT count(*) > 0 AS has_data FROM pg_stat_statements;
 
@@ -55,5 +56,6 @@ CREATE EXTENSION pg_stat_statements WITH VERSION '1.4';
 SELECT count(*) > 0 AS has_data FROM pg_stat_statements;
 -- New parameter minmax_only of pg_stat_statements_reset function
 SELECT pg_get_functiondef('pg_stat_statements_reset'::regproc);
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
 
 DROP EXTENSION pg_stat_statements;
-- 
2.43.0

From 6e023ad2bebd534b9ce7ac2697641d1759a8ecf0 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email-masked]>
Date: Sat, 23 Dec 2023 14:25:26 +0100
Subject: [PATCH v1 4/5] pg_stat_statements: Add coverage for entry_dealloc()

This involves creating pg_stat_statements.max entries, then creating
even more entries, and checking that the limit is kept and the least
used entries are kicked out.
---
 contrib/pg_stat_statements/Makefile           |    2 +-
 contrib/pg_stat_statements/expected/max.out   | 1127 +++++++++++++++++
 contrib/pg_stat_statements/meson.build        |    1 +
 .../pg_stat_statements.conf                   |    2 +
 contrib/pg_stat_statements/sql/max.sql        |   18 +
 5 files changed, 1149 insertions(+), 1 deletion(-)
 create mode 100644 contrib/pg_stat_statements/expected/max.out
 create mode 100644 contrib/pg_stat_statements/sql/max.sql

diff --git a/contrib/pg_stat_statements/Makefile b/contrib/pg_stat_statements/Makefile
index aecd1d6a2a..7ee16e8350 100644
--- a/contrib/pg_stat_statements/Makefile
+++ b/contrib/pg_stat_statements/Makefile
@@ -19,7 +19,7 @@ LDFLAGS_SL += $(filter -lm, $(LIBS))
 
 REGRESS_OPTS = --temp-config $(top_srcdir)/contrib/pg_stat_statements/pg_stat_statements.conf
 REGRESS = select dml cursors utility level_tracking planning \
-	user_activity wal entry_timestamp cleanup oldextversions
+	user_activity wal entry_timestamp max cleanup oldextversions
 # Disabled because these tests require "shared_preload_libraries=pg_stat_statements",
 # which typical installcheck users do not have (e.g. buildfarm clients).
 NO_INSTALLCHECK = 1
diff --git a/contrib/pg_stat_statements/expected/max.out b/contrib/pg_stat_statements/expected/max.out
new file mode 100644
index 0000000000..60750d15c2
--- /dev/null
+++ b/contrib/pg_stat_statements/expected/max.out
@@ -0,0 +1,1127 @@
+SHOW pg_stat_statements.max;
+ pg_stat_statements.max 
+------------------------
+ 100
+(1 row)
+
+SELECT format('create table t%s (a int)', lpad(i::text, 3, '0')) FROM generate_series(1, 101) AS x(i) \gexec
+create table t001 (a int)
+create table t002 (a int)
+create table t003 (a int)
+create table t004 (a int)
+create table t005 (a int)
+create table t006 (a int)
+create table t007 (a int)
+create table t008 (a int)
+create table t009 (a int)
+create table t010 (a int)
+create table t011 (a int)
+create table t012 (a int)
+create table t013 (a int)
+create table t014 (a int)
+create table t015 (a int)
+create table t016 (a int)
+create table t017 (a int)
+create table t018 (a int)
+create table t019 (a int)
+create table t020 (a int)
+create table t021 (a int)
+create table t022 (a int)
+create table t023 (a int)
+create table t024 (a int)
+create table t025 (a int)
+create table t026 (a int)
+create table t027 (a int)
+create table t028 (a int)
+create table t029 (a int)
+create table t030 (a int)
+create table t031 (a int)
+create table t032 (a int)
+create table t033 (a int)
+create table t034 (a int)
+create table t035 (a int)
+create table t036 (a int)
+create table t037 (a int)
+create table t038 (a int)
+create table t039 (a int)
+create table t040 (a int)
+create table t041 (a int)
+create table t042 (a int)
+create table t043 (a int)
+create table t044 (a int)
+create table t045 (a int)
+create table t046 (a int)
+create table t047 (a int)
+create table t048 (a int)
+create table t049 (a int)
+create table t050 (a int)
+create table t051 (a int)
+create table t052 (a int)
+create table t053 (a int)
+create table t054 (a int)
+create table t055 (a int)
+create table t056 (a int)
+create table t057 (a int)
+create table t058 (a int)
+create table t059 (a int)
+create table t060 (a int)
+create table t061 (a int)
+create table t062 (a int)
+create table t063 (a int)
+create table t064 (a int)
+create table t065 (a int)
+create table t066 (a int)
+create table t067 (a int)
+create table t068 (a int)
+create table t069 (a int)
+create table t070 (a int)
+create table t071 (a int)
+create table t072 (a int)
+create table t073 (a int)
+create table t074 (a int)
+create table t075 (a int)
+create table t076 (a int)
+create table t077 (a int)
+create table t078 (a int)
+create table t079 (a int)
+create table t080 (a int)
+create table t081 (a int)
+create table t082 (a int)
+create table t083 (a int)
+create table t084 (a int)
+create table t085 (a int)
+create table t086 (a int)
+create table t087 (a int)
+create table t088 (a int)
+create table t089 (a int)
+create table t090 (a int)
+create table t091 (a int)
+create table t092 (a int)
+create table t093 (a int)
+create table t094 (a int)
+create table t095 (a int)
+create table t096 (a int)
+create table t097 (a int)
+create table t098 (a int)
+create table t099 (a int)
+create table t100 (a int)
+create table t101 (a int)
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+ t 
+---
+ t
+(1 row)
+
+SELECT format('select * from t%s', lpad(i::text, 3, '0')) FROM generate_series(1, 98) AS x(i) \gexec
+select * from t001
+ a 
+---
+(0 rows)
+
+select * from t002
+ a 
+---
+(0 rows)
+
+select * from t003
+ a 
+---
+(0 rows)
+
+select * from t004
+ a 
+---
+(0 rows)
+
+select * from t005
+ a 
+---
+(0 rows)
+
+select * from t006
+ a 
+---
+(0 rows)
+
+select * from t007
+ a 
+---
+(0 rows)
+
+select * from t008
+ a 
+---
+(0 rows)
+
+select * from t009
+ a 
+---
+(0 rows)
+
+select * from t010
+ a 
+---
+(0 rows)
+
+select * from t011
+ a 
+---
+(0 rows)
+
+select * from t012
+ a 
+---
+(0 rows)
+
+select * from t013
+ a 
+---
+(0 rows)
+
+select * from t014
+ a 
+---
+(0 rows)
+
+select * from t015
+ a 
+---
+(0 rows)
+
+select * from t016
+ a 
+---
+(0 rows)
+
+select * from t017
+ a 
+---
+(0 rows)
+
+select * from t018
+ a 
+---
+(0 rows)
+
+select * from t019
+ a 
+---
+(0 rows)
+
+select * from t020
+ a 
+---
+(0 rows)
+
+select * from t021
+ a 
+---
+(0 rows)
+
+select * from t022
+ a 
+---
+(0 rows)
+
+select * from t023
+ a 
+---
+(0 rows)
+
+select * from t024
+ a 
+---
+(0 rows)
+
+select * from t025
+ a 
+---
+(0 rows)
+
+select * from t026
+ a 
+---
+(0 rows)
+
+select * from t027
+ a 
+---
+(0 rows)
+
+select * from t028
+ a 
+---
+(0 rows)
+
+select * from t029
+ a 
+---
+(0 rows)
+
+select * from t030
+ a 
+---
+(0 rows)
+
+select * from t031
+ a 
+---
+(0 rows)
+
+select * from t032
+ a 
+---
+(0 rows)
+
+select * from t033
+ a 
+---
+(0 rows)
+
+select * from t034
+ a 
+---
+(0 rows)
+
+select * from t035
+ a 
+---
+(0 rows)
+
+select * from t036
+ a 
+---
+(0 rows)
+
+select * from t037
+ a 
+---
+(0 rows)
+
+select * from t038
+ a 
+---
+(0 rows)
+
+select * from t039
+ a 
+---
+(0 rows)
+
+select * from t040
+ a 
+---
+(0 rows)
+
+select * from t041
+ a 
+---
+(0 rows)
+
+select * from t042
+ a 
+---
+(0 rows)
+
+select * from t043
+ a 
+---
+(0 rows)
+
+select * from t044
+ a 
+---
+(0 rows)
+
+select * from t045
+ a 
+---
+(0 rows)
+
+select * from t046
+ a 
+---
+(0 rows)
+
+select * from t047
+ a 
+---
+(0 rows)
+
+select * from t048
+ a 
+---
+(0 rows)
+
+select * from t049
+ a 
+---
+(0 rows)
+
+select * from t050
+ a 
+---
+(0 rows)
+
+select * from t051
+ a 
+---
+(0 rows)
+
+select * from t052
+ a 
+---
+(0 rows)
+
+select * from t053
+ a 
+---
+(0 rows)
+
+select * from t054
+ a 
+---
+(0 rows)
+
+select * from t055
+ a 
+---
+(0 rows)
+
+select * from t056
+ a 
+---
+(0 rows)
+
+select * from t057
+ a 
+---
+(0 rows)
+
+select * from t058
+ a 
+---
+(0 rows)
+
+select * from t059
+ a 
+---
+(0 rows)
+
+select * from t060
+ a 
+---
+(0 rows)
+
+select * from t061
+ a 
+---
+(0 rows)
+
+select * from t062
+ a 
+---
+(0 rows)
+
+select * from t063
+ a 
+---
+(0 rows)
+
+select * from t064
+ a 
+---
+(0 rows)
+
+select * from t065
+ a 
+---
+(0 rows)
+
+select * from t066
+ a 
+---
+(0 rows)
+
+select * from t067
+ a 
+---
+(0 rows)
+
+select * from t068
+ a 
+---
+(0 rows)
+
+select * from t069
+ a 
+---
+(0 rows)
+
+select * from t070
+ a 
+---
+(0 rows)
+
+select * from t071
+ a 
+---
+(0 rows)
+
+select * from t072
+ a 
+---
+(0 rows)
+
+select * from t073
+ a 
+---
+(0 rows)
+
+select * from t074
+ a 
+---
+(0 rows)
+
+select * from t075
+ a 
+---
+(0 rows)
+
+select * from t076
+ a 
+---
+(0 rows)
+
+select * from t077
+ a 
+---
+(0 rows)
+
+select * from t078
+ a 
+---
+(0 rows)
+
+select * from t079
+ a 
+---
+(0 rows)
+
+select * from t080
+ a 
+---
+(0 rows)
+
+select * from t081
+ a 
+---
+(0 rows)
+
+select * from t082
+ a 
+---
+(0 rows)
+
+select * from t083
+ a 
+---
+(0 rows)
+
+select * from t084
+ a 
+---
+(0 rows)
+
+select * from t085
+ a 
+---
+(0 rows)
+
+select * from t086
+ a 
+---
+(0 rows)
+
+select * from t087
+ a 
+---
+(0 rows)
+
+select * from t088
+ a 
+---
+(0 rows)
+
+select * from t089
+ a 
+---
+(0 rows)
+
+select * from t090
+ a 
+---
+(0 rows)
+
+select * from t091
+ a 
+---
+(0 rows)
+
+select * from t092
+ a 
+---
+(0 rows)
+
+select * from t093
+ a 
+---
+(0 rows)
+
+select * from t094
+ a 
+---
+(0 rows)
+
+select * from t095
+ a 
+---
+(0 rows)
+
+select * from t096
+ a 
+---
+(0 rows)
+
+select * from t097
+ a 
+---
+(0 rows)
+
+select * from t098
+ a 
+---
+(0 rows)
+
+SELECT count(*) <= 100 AND count(*) > 0 FROM pg_stat_statements;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT query FROM pg_stat_statements WHERE query LIKE '%t001%' OR query LIKE '%t098%' ORDER BY query;
+       query        
+--------------------
+ select * from t001
+ select * from t098
+(2 rows)
+
+SELECT format('select * from t%s', lpad(i::text, 3, '0')) from generate_series(2, 98) AS x(i) \gexec
+select * from t002
+ a 
+---
+(0 rows)
+
+select * from t003
+ a 
+---
+(0 rows)
+
+select * from t004
+ a 
+---
+(0 rows)
+
+select * from t005
+ a 
+---
+(0 rows)
+
+select * from t006
+ a 
+---
+(0 rows)
+
+select * from t007
+ a 
+---
+(0 rows)
+
+select * from t008
+ a 
+---
+(0 rows)
+
+select * from t009
+ a 
+---
+(0 rows)
+
+select * from t010
+ a 
+---
+(0 rows)
+
+select * from t011
+ a 
+---
+(0 rows)
+
+select * from t012
+ a 
+---
+(0 rows)
+
+select * from t013
+ a 
+---
+(0 rows)
+
+select * from t014
+ a 
+---
+(0 rows)
+
+select * from t015
+ a 
+---
+(0 rows)
+
+select * from t016
+ a 
+---
+(0 rows)
+
+select * from t017
+ a 
+---
+(0 rows)
+
+select * from t018
+ a 
+---
+(0 rows)
+
+select * from t019
+ a 
+---
+(0 rows)
+
+select * from t020
+ a 
+---
+(0 rows)
+
+select * from t021
+ a 
+---
+(0 rows)
+
+select * from t022
+ a 
+---
+(0 rows)
+
+select * from t023
+ a 
+---
+(0 rows)
+
+select * from t024
+ a 
+---
+(0 rows)
+
+select * from t025
+ a 
+---
+(0 rows)
+
+select * from t026
+ a 
+---
+(0 rows)
+
+select * from t027
+ a 
+---
+(0 rows)
+
+select * from t028
+ a 
+---
+(0 rows)
+
+select * from t029
+ a 
+---
+(0 rows)
+
+select * from t030
+ a 
+---
+(0 rows)
+
+select * from t031
+ a 
+---
+(0 rows)
+
+select * from t032
+ a 
+---
+(0 rows)
+
+select * from t033
+ a 
+---
+(0 rows)
+
+select * from t034
+ a 
+---
+(0 rows)
+
+select * from t035
+ a 
+---
+(0 rows)
+
+select * from t036
+ a 
+---
+(0 rows)
+
+select * from t037
+ a 
+---
+(0 rows)
+
+select * from t038
+ a 
+---
+(0 rows)
+
+select * from t039
+ a 
+---
+(0 rows)
+
+select * from t040
+ a 
+---
+(0 rows)
+
+select * from t041
+ a 
+---
+(0 rows)
+
+select * from t042
+ a 
+---
+(0 rows)
+
+select * from t043
+ a 
+---
+(0 rows)
+
+select * from t044
+ a 
+---
+(0 rows)
+
+select * from t045
+ a 
+---
+(0 rows)
+
+select * from t046
+ a 
+---
+(0 rows)
+
+select * from t047
+ a 
+---
+(0 rows)
+
+select * from t048
+ a 
+---
+(0 rows)
+
+select * from t049
+ a 
+---
+(0 rows)
+
+select * from t050
+ a 
+---
+(0 rows)
+
+select * from t051
+ a 
+---
+(0 rows)
+
+select * from t052
+ a 
+---
+(0 rows)
+
+select * from t053
+ a 
+---
+(0 rows)
+
+select * from t054
+ a 
+---
+(0 rows)
+
+select * from t055
+ a 
+---
+(0 rows)
+
+select * from t056
+ a 
+---
+(0 rows)
+
+select * from t057
+ a 
+---
+(0 rows)
+
+select * from t058
+ a 
+---
+(0 rows)
+
+select * from t059
+ a 
+---
+(0 rows)
+
+select * from t060
+ a 
+---
+(0 rows)
+
+select * from t061
+ a 
+---
+(0 rows)
+
+select * from t062
+ a 
+---
+(0 rows)
+
+select * from t063
+ a 
+---
+(0 rows)
+
+select * from t064
+ a 
+---
+(0 rows)
+
+select * from t065
+ a 
+---
+(0 rows)
+
+select * from t066
+ a 
+---
+(0 rows)
+
+select * from t067
+ a 
+---
+(0 rows)
+
+select * from t068
+ a 
+---
+(0 rows)
+
+select * from t069
+ a 
+---
+(0 rows)
+
+select * from t070
+ a 
+---
+(0 rows)
+
+select * from t071
+ a 
+---
+(0 rows)
+
+select * from t072
+ a 
+---
+(0 rows)
+
+select * from t073
+ a 
+---
+(0 rows)
+
+select * from t074
+ a 
+---
+(0 rows)
+
+select * from t075
+ a 
+---
+(0 rows)
+
+select * from t076
+ a 
+---
+(0 rows)
+
+select * from t077
+ a 
+---
+(0 rows)
+
+select * from t078
+ a 
+---
+(0 rows)
+
+select * from t079
+ a 
+---
+(0 rows)
+
+select * from t080
+ a 
+---
+(0 rows)
+
+select * from t081
+ a 
+---
+(0 rows)
+
+select * from t082
+ a 
+---
+(0 rows)
+
+select * from t083
+ a 
+---
+(0 rows)
+
+select * from t084
+ a 
+---
+(0 rows)
+
+select * from t085
+ a 
+---
+(0 rows)
+
+select * from t086
+ a 
+---
+(0 rows)
+
+select * from t087
+ a 
+---
+(0 rows)
+
+select * from t088
+ a 
+---
+(0 rows)
+
+select * from t089
+ a 
+---
+(0 rows)
+
+select * from t090
+ a 
+---
+(0 rows)
+
+select * from t091
+ a 
+---
+(0 rows)
+
+select * from t092
+ a 
+---
+(0 rows)
+
+select * from t093
+ a 
+---
+(0 rows)
+
+select * from t094
+ a 
+---
+(0 rows)
+
+select * from t095
+ a 
+---
+(0 rows)
+
+select * from t096
+ a 
+---
+(0 rows)
+
+select * from t097
+ a 
+---
+(0 rows)
+
+select * from t098
+ a 
+---
+(0 rows)
+
+SELECT format('select * from t%s', lpad(i::text, 3, '0')) from generate_series(99, 100) AS x(i) \gexec
+select * from t099
+ a 
+---
+(0 rows)
+
+select * from t100
+ a 
+---
+(0 rows)
+
+SELECT count(*) <= 100 AND count(*) > 0 FROM pg_stat_statements;
+ ?column? 
+----------
+ t
+(1 row)
+
+-- record for t001 has been kicked out
+SELECT query FROM pg_stat_statements WHERE query LIKE '%t001%' ORDER BY query;
+ query 
+-------
+(0 rows)
+
diff --git a/contrib/pg_stat_statements/meson.build b/contrib/pg_stat_statements/meson.build
index 81fe1eb917..a66acaa5b8 100644
--- a/contrib/pg_stat_statements/meson.build
+++ b/contrib/pg_stat_statements/meson.build
@@ -50,6 +50,7 @@ tests += {
       'user_activity',
       'wal',
       'entry_timestamp',
+      'max',
       'cleanup',
       'oldextversions',
     ],
diff --git a/contrib/pg_stat_statements/pg_stat_statements.conf b/contrib/pg_stat_statements/pg_stat_statements.conf
index 0e900d7119..0119f681d7 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.conf
+++ b/contrib/pg_stat_statements/pg_stat_statements.conf
@@ -1,2 +1,4 @@
 shared_preload_libraries = 'pg_stat_statements'
 max_prepared_transactions = 5
+
+pg_stat_statements.max = 100
diff --git a/contrib/pg_stat_statements/sql/max.sql b/contrib/pg_stat_statements/sql/max.sql
new file mode 100644
index 0000000000..ce6a1bd84e
--- /dev/null
+++ b/contrib/pg_stat_statements/sql/max.sql
@@ -0,0 +1,18 @@
+SHOW pg_stat_statements.max;
+
+SELECT format('create table t%s (a int)', lpad(i::text, 3, '0')) FROM generate_series(1, 101) AS x(i) \gexec
+
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+
+SELECT format('select * from t%s', lpad(i::text, 3, '0')) FROM generate_series(1, 98) AS x(i) \gexec
+
+SELECT count(*) <= 100 AND count(*) > 0 FROM pg_stat_statements;
+SELECT query FROM pg_stat_statements WHERE query LIKE '%t001%' OR query LIKE '%t098%' ORDER BY query;
+
+SELECT format('select * from t%s', lpad(i::text, 3, '0')) from generate_series(2, 98) AS x(i) \gexec
+
+SELECT format('select * from t%s', lpad(i::text, 3, '0')) from generate_series(99, 100) AS x(i) \gexec
+
+SELECT count(*) <= 100 AND count(*) > 0 FROM pg_stat_statements;
+-- record for t001 has been kicked out
+SELECT query FROM pg_stat_statements WHERE query LIKE '%t001%' ORDER BY query;
-- 
2.43.0

From b4a64f5e4fbf7b08e14caa680f88eebb09da2c69 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email-masked]>
Date: Sat, 23 Dec 2023 14:25:26 +0100
Subject: [PATCH v1 5/5] pg_stat_statements: Add TAP test for testing restarts

This tests that pg_stat_statement contents are successfully kept
across restart.  (This similar to
src/test/recovery/t/029_stats_restart.pl for the stats collector.)
---
 contrib/pg_stat_statements/Makefile         |  2 +
 contrib/pg_stat_statements/meson.build      |  5 +++
 contrib/pg_stat_statements/t/010_restart.pl | 50 +++++++++++++++++++++
 3 files changed, 57 insertions(+)
 create mode 100644 contrib/pg_stat_statements/t/010_restart.pl

diff --git a/contrib/pg_stat_statements/Makefile b/contrib/pg_stat_statements/Makefile
index 7ee16e8350..20834bb0ee 100644
--- a/contrib/pg_stat_statements/Makefile
+++ b/contrib/pg_stat_statements/Makefile
@@ -24,6 +24,8 @@ REGRESS = select dml cursors utility level_tracking planning \
 # which typical installcheck users do not have (e.g. buildfarm clients).
 NO_INSTALLCHECK = 1
 
+TAP_TESTS = 1
+
 ifdef USE_PGXS
 PG_CONFIG = pg_config
 PGXS := $(shell $(PG_CONFIG) --pgxs)
diff --git a/contrib/pg_stat_statements/meson.build b/contrib/pg_stat_statements/meson.build
index a66acaa5b8..3e42328f6c 100644
--- a/contrib/pg_stat_statements/meson.build
+++ b/contrib/pg_stat_statements/meson.build
@@ -60,4 +60,9 @@ tests += {
     # runningcheck users do not have (e.g. buildfarm clients).
     'runningcheck': false,
   },
+  'tap': {
+    'tests': [
+      't/010_restart.pl',
+    ],
+  },
 }
diff --git a/contrib/pg_stat_statements/t/010_restart.pl b/contrib/pg_stat_statements/t/010_restart.pl
new file mode 100644
index 0000000000..bf0fba6bda
--- /dev/null
+++ b/contrib/pg_stat_statements/t/010_restart.pl
@@ -0,0 +1,50 @@
+# Copyright (c) 2023, PostgreSQL Global Development Group
+
+# Tests for checking that pg_stat_statements contents are preserved
+# across restarts.
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+my $node = PostgreSQL::Test::Cluster->new('main');
+$node->init;
+$node->append_conf('postgresql.conf',
+	"shared_preload_libraries = 'pg_stat_statements'");
+$node->start;
+
+$node->safe_psql('postgres', 'CREATE EXTENSION pg_stat_statements');
+
+$node->safe_psql('postgres', 'CREATE TABLE t1 (a int)');
+$node->safe_psql('postgres', 'SELECT a FROM t1');
+
+is( $node->safe_psql(
+		'postgres',
+		"SELECT count(*) FROM pg_stat_statements WHERE query LIKE '%t1%'"),
+	'2',
+	'pg_stat_statements populated');
+
+$node->restart;
+
+is( $node->safe_psql(
+		'postgres',
+		"SELECT count(*) FROM pg_stat_statements WHERE query LIKE '%t1%'"),
+	'2',
+	'pg_stat_statements data kept across restart');
+
+$node->append_conf('postgresql.conf', "pg_stat_statements.save = false");
+$node->reload;
+
+$node->restart;
+
+is( $node->safe_psql(
+		'postgres',
+		"SELECT count(*) FROM pg_stat_statements WHERE query LIKE '%t1%'"),
+	'0',
+	'pg_stat_statements data not kept across restart with .save=false');
+
+$node->stop;
+
+done_testing();
-- 
2.43.0