summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorMichael Paquier <michael@paquier.xyz>2023-03-03 08:46:11 +0900
committerMichael Paquier <michael@paquier.xyz>2023-03-03 08:46:11 +0900
commitd0028e35a05ac71aebf28325c8ddb59a27cb63c0 (patch)
tree4397df3830406a1f7a0a38c499aadf681a69b09d /contrib
parent98a88bc2bcd60e41ca70e2f1e13eee827e23eefb (diff)
downloadpostgresql-d0028e35a05ac71aebf28325c8ddb59a27cb63c0.tar.gz
Refactor more the regression tests of pg_stat_statements
This commit expands more the refactoring of the regression tests of pg_stat_statements, with tests moved out of pg_stat_statements.sql into separate files. The following file structure is now used: - select is mostly the former pg_stat_statements.sql, renamed. - dml for INSERT/UPDATE/DELETE and MERGE - user_activity, to test role-level checks and stat resets. - wal, to check the WAL generation after some queries. Like e8dbdb1, there is no change in terms of code coverage or results, and this finishes the split I was aiming for in these tests. Most of the tests used "test" of "pgss_test" as names for the tables used, these are renamed to less generic names. Reviewed-by: Bertrand Drouvot Discussion: https://postgr.es/m/Y/7Y9U/y/keAW3qH@paquier.xyz
Diffstat (limited to 'contrib')
-rw-r--r--contrib/pg_stat_statements/Makefile4
-rw-r--r--contrib/pg_stat_statements/expected/dml.out147
-rw-r--r--contrib/pg_stat_statements/expected/pg_stat_statements.out768
-rw-r--r--contrib/pg_stat_statements/expected/select.out414
-rw-r--r--contrib/pg_stat_statements/expected/user_activity.out199
-rw-r--r--contrib/pg_stat_statements/expected/wal.out33
-rw-r--r--contrib/pg_stat_statements/meson.build5
-rw-r--r--contrib/pg_stat_statements/sql/dml.sql76
-rw-r--r--contrib/pg_stat_statements/sql/pg_stat_statements.sql300
-rw-r--r--contrib/pg_stat_statements/sql/select.sql149
-rw-r--r--contrib/pg_stat_statements/sql/user_activity.sql65
-rw-r--r--contrib/pg_stat_statements/sql/wal.sql20
12 files changed, 1109 insertions, 1071 deletions
diff --git a/contrib/pg_stat_statements/Makefile b/contrib/pg_stat_statements/Makefile
index 69fbc6a858..5578a9dd4e 100644
--- a/contrib/pg_stat_statements/Makefile
+++ b/contrib/pg_stat_statements/Makefile
@@ -17,8 +17,8 @@ PGFILEDESC = "pg_stat_statements - execution statistics of SQL statements"
LDFLAGS_SL += $(filter -lm, $(LIBS))
REGRESS_OPTS = --temp-config $(top_srcdir)/contrib/pg_stat_statements/pg_stat_statements.conf
-REGRESS = pg_stat_statements cursors utility level_tracking planning \
- cleanup oldextversions
+REGRESS = select dml cursors utility level_tracking planning \
+ user_activity wal 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/dml.out b/contrib/pg_stat_statements/expected/dml.out
new file mode 100644
index 0000000000..7b9c8f979e
--- /dev/null
+++ b/contrib/pg_stat_statements/expected/dml.out
@@ -0,0 +1,147 @@
+--
+-- DMLs on test table
+--
+SET pg_stat_statements.track_utility = FALSE;
+CREATE TEMP TABLE pgss_dml_tab (a int, b char(20));
+INSERT INTO pgss_dml_tab VALUES(generate_series(1, 10), 'aaa');
+UPDATE pgss_dml_tab SET b = 'bbb' WHERE a > 7;
+DELETE FROM pgss_dml_tab WHERE a > 9;
+-- explicit transaction
+BEGIN;
+UPDATE pgss_dml_tab SET b = '111' WHERE a = 1 ;
+COMMIT;
+BEGIN \;
+UPDATE pgss_dml_tab SET b = '222' WHERE a = 2 \;
+COMMIT ;
+UPDATE pgss_dml_tab SET b = '333' WHERE a = 3 \;
+UPDATE pgss_dml_tab SET b = '444' WHERE a = 4 ;
+BEGIN \;
+UPDATE pgss_dml_tab SET b = '555' WHERE a = 5 \;
+UPDATE pgss_dml_tab SET b = '666' WHERE a = 6 \;
+COMMIT ;
+-- many INSERT values
+INSERT INTO pgss_dml_tab (a, b) VALUES (1, 'a'), (2, 'b'), (3, 'c');
+-- SELECT with constants
+SELECT * FROM pgss_dml_tab WHERE a > 5 ORDER BY a ;
+ a | b
+---+----------------------
+ 6 | 666
+ 7 | aaa
+ 8 | bbb
+ 9 | bbb
+(4 rows)
+
+SELECT *
+ FROM pgss_dml_tab
+ WHERE a > 9
+ ORDER BY a ;
+ a | b
+---+---
+(0 rows)
+
+-- these two need to be done on a different table
+-- SELECT without constants
+SELECT * FROM pgss_dml_tab ORDER BY a;
+ a | b
+---+----------------------
+ 1 | a
+ 1 | 111
+ 2 | b
+ 2 | 222
+ 3 | c
+ 3 | 333
+ 4 | 444
+ 5 | 555
+ 6 | 666
+ 7 | aaa
+ 8 | bbb
+ 9 | bbb
+(12 rows)
+
+-- SELECT with IN clause
+SELECT * FROM pgss_dml_tab WHERE a IN (1, 2, 3, 4, 5);
+ a | b
+---+----------------------
+ 1 | 111
+ 2 | 222
+ 3 | 333
+ 4 | 444
+ 5 | 555
+ 1 | a
+ 2 | b
+ 3 | c
+(8 rows)
+
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+ calls | rows | query
+-------+------+---------------------------------------------------------------------
+ 1 | 1 | DELETE FROM pgss_dml_tab WHERE a > $1
+ 1 | 3 | INSERT INTO pgss_dml_tab (a, b) VALUES ($1, $2), ($3, $4), ($5, $6)
+ 1 | 10 | INSERT INTO pgss_dml_tab VALUES(generate_series($1, $2), $3)
+ 1 | 12 | SELECT * FROM pgss_dml_tab ORDER BY a
+ 2 | 4 | SELECT * FROM pgss_dml_tab WHERE a > $1 ORDER BY a
+ 1 | 8 | SELECT * FROM pgss_dml_tab WHERE a IN ($1, $2, $3, $4, $5)
+ 1 | 1 | SELECT pg_stat_statements_reset()
+ 1 | 0 | SET pg_stat_statements.track_utility = FALSE
+ 6 | 6 | UPDATE pgss_dml_tab SET b = $1 WHERE a = $2
+ 1 | 3 | UPDATE pgss_dml_tab SET b = $1 WHERE a > $2
+(10 rows)
+
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+-- MERGE
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= 4)
+ WHEN MATCHED THEN UPDATE SET b = st.b || st.a::text;
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= 4)
+ WHEN MATCHED THEN UPDATE SET b = pgss_dml_tab.b || st.a::text;
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= 4)
+ WHEN MATCHED AND length(st.b) > 1 THEN UPDATE SET b = pgss_dml_tab.b || st.a::text;
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a)
+ WHEN NOT MATCHED THEN INSERT (a, b) VALUES (0, NULL);
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a)
+ WHEN NOT MATCHED THEN INSERT VALUES (0, NULL); -- same as above
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a)
+ WHEN NOT MATCHED THEN INSERT (b, a) VALUES (NULL, 0);
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a)
+ WHEN NOT MATCHED THEN INSERT (a) VALUES (0);
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= 4)
+ WHEN MATCHED THEN DELETE;
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= 4)
+ WHEN MATCHED THEN DO NOTHING;
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= 4)
+ WHEN NOT MATCHED THEN DO NOTHING;
+DROP TABLE pgss_dml_tab;
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+ calls | rows | query
+-------+------+-----------------------------------------------------------------------------------------
+ 1 | 6 | MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= $1)+
+ | | WHEN MATCHED AND length(st.b) > $2 THEN UPDATE SET b = pgss_dml_tab.b || st.a::text
+ 1 | 6 | MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= $1)+
+ | | WHEN MATCHED THEN DELETE
+ 1 | 0 | MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= $1)+
+ | | WHEN MATCHED THEN DO NOTHING
+ 1 | 6 | MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= $1)+
+ | | WHEN MATCHED THEN UPDATE SET b = pgss_dml_tab.b || st.a::text
+ 1 | 6 | MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= $1)+
+ | | WHEN MATCHED THEN UPDATE SET b = st.b || st.a::text
+ 1 | 0 | MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= $1)+
+ | | WHEN NOT MATCHED THEN DO NOTHING
+ 1 | 0 | MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a) +
+ | | WHEN NOT MATCHED THEN INSERT (a) VALUES ($1)
+ 2 | 0 | MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a) +
+ | | WHEN NOT MATCHED THEN INSERT (a, b) VALUES ($1, $2)
+ 1 | 0 | MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a) +
+ | | WHEN NOT MATCHED THEN INSERT (b, a) VALUES ($1, $2)
+ 1 | 1 | SELECT pg_stat_statements_reset()
+(10 rows)
+
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
diff --git a/contrib/pg_stat_statements/expected/pg_stat_statements.out b/contrib/pg_stat_statements/expected/pg_stat_statements.out
deleted file mode 100644
index 2c5bed841a..0000000000
--- a/contrib/pg_stat_statements/expected/pg_stat_statements.out
+++ /dev/null
@@ -1,768 +0,0 @@
-CREATE EXTENSION pg_stat_statements;
---
--- simple and compound statements
---
-SET pg_stat_statements.track_utility = FALSE;
-SET pg_stat_statements.track_planning = TRUE;
-SELECT pg_stat_statements_reset();
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
-SELECT 1 AS "int";
- int
------
- 1
-(1 row)
-
-SELECT 'hello'
- -- multiline
- AS "text";
- text
--------
- hello
-(1 row)
-
-SELECT 'world' AS "text";
- text
--------
- world
-(1 row)
-
--- transaction
-BEGIN;
-SELECT 1 AS "int";
- int
------
- 1
-(1 row)
-
-SELECT 'hello' AS "text";
- text
--------
- hello
-(1 row)
-
-COMMIT;
--- compound transaction
-BEGIN \;
-SELECT 2.0 AS "float" \;
-SELECT 'world' AS "text" \;
-COMMIT;
- float
--------
- 2.0
-(1 row)
-
- text
--------
- world
-(1 row)
-
--- compound with empty statements and spurious leading spacing
-\;\; SELECT 3 + 3 \;\;\; SELECT ' ' || ' !' \;\; SELECT 1 + 4 \;;
- ?column?
-----------
- 6
-(1 row)
-
- ?column?
-----------
- !
-(1 row)
-
- ?column?
-----------
- 5
-(1 row)
-
--- non ;-terminated statements
-SELECT 1 + 1 + 1 AS "add" \gset
-SELECT :add + 1 + 1 AS "add" \;
-SELECT :add + 1 + 1 AS "add" \gset
- add
------
- 5
-(1 row)
-
--- set operator
-SELECT 1 AS i UNION SELECT 2 ORDER BY i;
- i
----
- 1
- 2
-(2 rows)
-
--- ? operator
-select '{"a":1, "b":2}'::jsonb ? 'b';
- ?column?
-----------
- t
-(1 row)
-
--- cte
-WITH t(f) AS (
- VALUES (1.0), (2.0)
-)
- SELECT f FROM t ORDER BY f;
- f
------
- 1.0
- 2.0
-(2 rows)
-
--- prepared statement with parameter
-PREPARE pgss_test (int) AS SELECT $1, 'test' LIMIT 1;
-EXECUTE pgss_test(1);
- ?column? | ?column?
-----------+----------
- 1 | test
-(1 row)
-
-DEALLOCATE pgss_test;
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
- query | calls | rows
-------------------------------------------------------------------------------+-------+------
- PREPARE pgss_test (int) AS SELECT $1, $2 LIMIT $3 | 1 | 1
- SELECT $1 +| 4 | 4
- -- multiline +| |
- AS "text" | |
- SELECT $1 + $2 | 2 | 2
- SELECT $1 + $2 + $3 AS "add" | 3 | 3
- SELECT $1 AS "float" | 1 | 1
- SELECT $1 AS "int" | 2 | 2
- SELECT $1 AS i UNION SELECT $2 ORDER BY i | 1 | 2
- SELECT $1 || $2 | 1 | 1
- SELECT pg_stat_statements_reset() | 1 | 1
- SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 0 | 0
- WITH t(f) AS ( +| 1 | 2
- VALUES ($1), ($2) +| |
- ) +| |
- SELECT f FROM t ORDER BY f | |
- select $1::jsonb ? $2 | 1 | 1
-(12 rows)
-
---
--- CRUD: INSERT SELECT UPDATE DELETE on test table
---
-SELECT pg_stat_statements_reset();
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
--- utility "create table" should not be shown
-CREATE TEMP TABLE test (a int, b char(20));
-INSERT INTO test VALUES(generate_series(1, 10), 'aaa');
-UPDATE test SET b = 'bbb' WHERE a > 7;
-DELETE FROM test WHERE a > 9;
--- explicit transaction
-BEGIN;
-UPDATE test SET b = '111' WHERE a = 1 ;
-COMMIT;
-BEGIN \;
-UPDATE test SET b = '222' WHERE a = 2 \;
-COMMIT ;
-UPDATE test SET b = '333' WHERE a = 3 \;
-UPDATE test SET b = '444' WHERE a = 4 ;
-BEGIN \;
-UPDATE test SET b = '555' WHERE a = 5 \;
-UPDATE test SET b = '666' WHERE a = 6 \;
-COMMIT ;
--- many INSERT values
-INSERT INTO test (a, b) VALUES (1, 'a'), (2, 'b'), (3, 'c');
--- SELECT with constants
-SELECT * FROM test WHERE a > 5 ORDER BY a ;
- a | b
----+----------------------
- 6 | 666
- 7 | aaa
- 8 | bbb
- 9 | bbb
-(4 rows)
-
-SELECT *
- FROM test
- WHERE a > 9
- ORDER BY a ;
- a | b
----+---
-(0 rows)
-
--- SELECT without constants
-SELECT * FROM test ORDER BY a;
- a | b
----+----------------------
- 1 | a
- 1 | 111
- 2 | b
- 2 | 222
- 3 | c
- 3 | 333
- 4 | 444
- 5 | 555
- 6 | 666
- 7 | aaa
- 8 | bbb
- 9 | bbb
-(12 rows)
-
--- SELECT with IN clause
-SELECT * FROM test WHERE a IN (1, 2, 3, 4, 5);
- a | b
----+----------------------
- 1 | 111
- 2 | 222
- 3 | 333
- 4 | 444
- 5 | 555
- 1 | a
- 2 | b
- 3 | c
-(8 rows)
-
--- MERGE
-MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4)
- WHEN MATCHED THEN UPDATE SET b = st.b || st.a::text;
-MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4)
- WHEN MATCHED THEN UPDATE SET b = test.b || st.a::text;
-MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4)
- WHEN MATCHED AND length(st.b) > 1 THEN UPDATE SET b = test.b || st.a::text;
-MERGE INTO test USING test st ON (st.a = test.a)
- WHEN NOT MATCHED THEN INSERT (a, b) VALUES (0, NULL);
-MERGE INTO test USING test st ON (st.a = test.a)
- WHEN NOT MATCHED THEN INSERT VALUES (0, NULL); -- same as above
-MERGE INTO test USING test st ON (st.a = test.a)
- WHEN NOT MATCHED THEN INSERT (b, a) VALUES (NULL, 0);
-MERGE INTO test USING test st ON (st.a = test.a)
- WHEN NOT MATCHED THEN INSERT (a) VALUES (0);
-MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4)
- WHEN MATCHED THEN DELETE;
-MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4)
- WHEN MATCHED THEN DO NOTHING;
-MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4)
- WHEN NOT MATCHED THEN DO NOTHING;
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
- query | calls | rows
-------------------------------------------------------------------------------+-------+------
- DELETE FROM test WHERE a > $1 | 1 | 1
- INSERT INTO test (a, b) VALUES ($1, $2), ($3, $4), ($5, $6) | 1 | 3
- INSERT INTO test VALUES(generate_series($1, $2), $3) | 1 | 10
- MERGE INTO test USING test st ON (st.a = test.a AND st.a >= $1) +| 1 | 6
- WHEN MATCHED AND length(st.b) > $2 THEN UPDATE SET b = test.b || st.a::text | |
- MERGE INTO test USING test st ON (st.a = test.a AND st.a >= $1) +| 1 | 6
- WHEN MATCHED THEN DELETE | |
- MERGE INTO test USING test st ON (st.a = test.a AND st.a >= $1) +| 1 | 0
- WHEN MATCHED THEN DO NOTHING | |
- MERGE INTO test USING test st ON (st.a = test.a AND st.a >= $1) +| 1 | 6
- WHEN MATCHED THEN UPDATE SET b = st.b || st.a::text | |
- MERGE INTO test USING test st ON (st.a = test.a AND st.a >= $1) +| 1 | 6
- WHEN MATCHED THEN UPDATE SET b = test.b || st.a::text | |
- MERGE INTO test USING test st ON (st.a = test.a AND st.a >= $1) +| 1 | 0
- WHEN NOT MATCHED THEN DO NOTHING | |
- MERGE INTO test USING test st ON (st.a = test.a) +| 1 | 0
- WHEN NOT MATCHED THEN INSERT (a) VALUES ($1) | |
- MERGE INTO test USING test st ON (st.a = test.a) +| 2 | 0
- WHEN NOT MATCHED THEN INSERT (a, b) VALUES ($1, $2) | |
- MERGE INTO test USING test st ON (st.a = test.a) +| 1 | 0
- WHEN NOT MATCHED THEN INSERT (b, a) VALUES ($1, $2) | |
- SELECT * FROM test ORDER BY a | 1 | 12
- SELECT * FROM test WHERE a > $1 ORDER BY a | 2 | 4
- SELECT * FROM test WHERE a IN ($1, $2, $3, $4, $5) | 1 | 8
- SELECT pg_stat_statements_reset() | 1 | 1
- SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 0 | 0
- UPDATE test SET b = $1 WHERE a = $2 | 6 | 6
- UPDATE test SET b = $1 WHERE a > $2 | 1 | 3
-(19 rows)
-
---
--- INSERT, UPDATE, DELETE on test table to validate WAL generation metrics
---
-SELECT pg_stat_statements_reset();
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
--- utility "create table" should not be shown
-CREATE TABLE pgss_test (a int, b char(20));
-INSERT INTO pgss_test VALUES(generate_series(1, 10), 'aaa');
-UPDATE pgss_test SET b = 'bbb' WHERE a > 7;
-DELETE FROM pgss_test WHERE a > 9;
--- DROP test table
-DROP TABLE pgss_test;
--- Check WAL is generated for the above statements
-SELECT query, calls, rows,
-wal_bytes > 0 as wal_bytes_generated,
-wal_records > 0 as wal_records_generated,
-wal_records >= rows as wal_records_ge_rows
-FROM pg_stat_statements ORDER BY query COLLATE "C";
- query | calls | rows | wal_bytes_generated | wal_records_generated | wal_records_ge_rows
------------------------------------------------------------+-------+------+---------------------+-----------------------+---------------------
- DELETE FROM pgss_test WHERE a > $1 | 1 | 1 | t | t | t
- INSERT INTO pgss_test VALUES(generate_series($1, $2), $3) | 1 | 10 | t | t | t
- SELECT pg_stat_statements_reset() | 1 | 1 | f | f | f
- SELECT query, calls, rows, +| 0 | 0 | f | f | t
- wal_bytes > $1 as wal_bytes_generated, +| | | | |
- wal_records > $2 as wal_records_generated, +| | | | |
- wal_records >= rows as wal_records_ge_rows +| | | | |
- FROM pg_stat_statements ORDER BY query COLLATE "C" | | | | |
- UPDATE pgss_test SET b = $1 WHERE a > $2 | 1 | 3 | t | t | t
-(5 rows)
-
---
--- queries with locking clauses
---
-CREATE TABLE pgss_a (id integer PRIMARY KEY);
-CREATE TABLE pgss_b (id integer PRIMARY KEY, a_id integer REFERENCES pgss_a);
-SELECT pg_stat_statements_reset();
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
--- control query
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id;
- id | id | a_id
-----+----+------
-(0 rows)
-
--- test range tables
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE;
- id | id | a_id
-----+----+------
-(0 rows)
-
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a;
- id | id | a_id
-----+----+------
-(0 rows)
-
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b;
- id | id | a_id
-----+----+------
-(0 rows)
-
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a, pgss_b; -- matches plain "FOR UPDATE"
- id | id | a_id
-----+----+------
-(0 rows)
-
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b, pgss_a;
- id | id | a_id
-----+----+------
-(0 rows)
-
--- test strengths
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR NO KEY UPDATE;
- id | id | a_id
-----+----+------
-(0 rows)
-
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR SHARE;
- id | id | a_id
-----+----+------
-(0 rows)
-
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR KEY SHARE;
- id | id | a_id
-----+----+------
-(0 rows)
-
--- test wait policies
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE NOWAIT;
- id | id | a_id
-----+----+------
-(0 rows)
-
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE SKIP LOCKED;
- id | id | a_id
-----+----+------
-(0 rows)
-
-SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C";
- calls | query
--------+------------------------------------------------------------------------------------------
- 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id
- 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR KEY SHARE
- 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR NO KEY UPDATE
- 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR SHARE
- 2 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE
- 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE NOWAIT
- 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a
- 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b
- 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b, pgss_a
- 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE SKIP LOCKED
- 0 | SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C"
- 1 | SELECT pg_stat_statements_reset()
-(12 rows)
-
-DROP TABLE pgss_a, pgss_b CASCADE;
---
--- Track user activity and reset them
---
-SET pg_stat_statements.track_utility = TRUE;
-SELECT pg_stat_statements_reset();
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
-CREATE ROLE regress_stats_user1;
-CREATE ROLE regress_stats_user2;
-SET ROLE regress_stats_user1;
-SELECT 1 AS "ONE";
- ONE
------
- 1
-(1 row)
-
-SELECT 1+1 AS "TWO";
- TWO
------
- 2
-(1 row)
-
-RESET ROLE;
-SET ROLE regress_stats_user2;
-SELECT 1 AS "ONE";
- ONE
------
- 1
-(1 row)
-
-SELECT 1+1 AS "TWO";
- TWO
------
- 2
-(1 row)
-
-RESET ROLE;
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
- query | calls | rows
-------------------------------------------------------------------------------+-------+------
- CREATE ROLE regress_stats_user1 | 1 | 0
- CREATE ROLE regress_stats_user2 | 1 | 0
- RESET ROLE | 2 | 0
- SELECT $1 AS "ONE" | 1 | 1
- SELECT $1 AS "ONE" | 1 | 1
- SELECT $1+$2 AS "TWO" | 1 | 1
- SELECT $1+$2 AS "TWO" | 1 | 1
- SELECT pg_stat_statements_reset() | 1 | 1
- SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 0 | 0
- SET ROLE regress_stats_user1 | 1 | 0
- SET ROLE regress_stats_user2 | 1 | 0
-(11 rows)
-
---
--- Don't reset anything if any of the parameter is NULL
---
-SELECT pg_stat_statements_reset(NULL);
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
- query | calls | rows
-------------------------------------------------------------------------------+-------+------
- CREATE ROLE regress_stats_user1 | 1 | 0
- CREATE ROLE regress_stats_user2 | 1 | 0
- RESET ROLE | 2 | 0
- SELECT $1 AS "ONE" | 1 | 1
- SELECT $1 AS "ONE" | 1 | 1
- SELECT $1+$2 AS "TWO" | 1 | 1
- SELECT $1+$2 AS "TWO" | 1 | 1
- SELECT pg_stat_statements_reset($1) | 1 | 1
- SELECT pg_stat_statements_reset() | 1 | 1
- SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 1 | 11
- SET ROLE regress_stats_user1 | 1 | 0
- SET ROLE regress_stats_user2 | 1 | 0
-(12 rows)
-
---
--- remove query ('SELECT $1+$2 AS "TWO"') executed by regress_stats_user2
--- in the current_database
---
-SELECT pg_stat_statements_reset(
- (SELECT r.oid FROM pg_roles AS r WHERE r.rolname = 'regress_stats_user2'),
- (SELECT d.oid FROM pg_database As d where datname = current_database()),
- (SELECT s.queryid FROM pg_stat_statements AS s
- WHERE s.query = 'SELECT $1+$2 AS "TWO"' LIMIT 1));
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
- query | calls | rows
-----------------------------------------------------------------------------------+-------+------
- CREATE ROLE regress_stats_user1 | 1 | 0
- CREATE ROLE regress_stats_user2 | 1 | 0
- RESET ROLE | 2 | 0
- SELECT $1 AS "ONE" | 1 | 1
- SELECT $1 AS "ONE" | 1 | 1
- SELECT $1+$2 AS "TWO" | 1 | 1
- SELECT pg_stat_statements_reset( +| 1 | 1
- (SELECT r.oid FROM pg_roles AS r WHERE r.rolname = $1), +| |
- (SELECT d.oid FROM pg_database As d where datname = current_database()),+| |
- (SELECT s.queryid FROM pg_stat_statements AS s +| |
- WHERE s.query = $2 LIMIT $3)) | |
- SELECT pg_stat_statements_reset($1) | 1 | 1
- SELECT pg_stat_statements_reset() | 1 | 1
- SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 2 | 23
- SET ROLE regress_stats_user1 | 1 | 0
- SET ROLE regress_stats_user2 | 1 | 0
-(12 rows)
-
---
--- remove query ('SELECT $1 AS "ONE"') executed by two users
---
-SELECT pg_stat_statements_reset(0,0,s.queryid)
- FROM pg_stat_statements AS s WHERE s.query = 'SELECT $1 AS "ONE"';
- pg_stat_statements_reset
---------------------------
-
-
-(2 rows)
-
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
- query | calls | rows
-----------------------------------------------------------------------------------+-------+------
- CREATE ROLE regress_stats_user1 | 1 | 0
- CREATE ROLE regress_stats_user2 | 1 | 0
- RESET ROLE | 2 | 0
- SELECT $1+$2 AS "TWO" | 1 | 1
- SELECT pg_stat_statements_reset( +| 1 | 1
- (SELECT r.oid FROM pg_roles AS r WHERE r.rolname = $1), +| |
- (SELECT d.oid FROM pg_database As d where datname = current_database()),+| |
- (SELECT s.queryid FROM pg_stat_statements AS s +| |
- WHERE s.query = $2 LIMIT $3)) | |
- SELECT pg_stat_statements_reset($1) | 1 | 1
- SELECT pg_stat_statements_reset($1,$2,s.queryid) +| 1 | 2
- FROM pg_stat_statements AS s WHERE s.query = $3 | |
- SELECT pg_stat_statements_reset() | 1 | 1
- SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 3 | 35
- SET ROLE regress_stats_user1 | 1 | 0
- SET ROLE regress_stats_user2 | 1 | 0
-(11 rows)
-
---
--- remove query of a user (regress_stats_user1)
---
-SELECT pg_stat_statements_reset(r.oid)
- FROM pg_roles AS r WHERE r.rolname = 'regress_stats_user1';
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
- query | calls | rows
-----------------------------------------------------------------------------------+-------+------
- CREATE ROLE regress_stats_user1 | 1 | 0
- CREATE ROLE regress_stats_user2 | 1 | 0
- RESET ROLE | 2 | 0
- SELECT pg_stat_statements_reset( +| 1 | 1
- (SELECT r.oid FROM pg_roles AS r WHERE r.rolname = $1), +| |
- (SELECT d.oid FROM pg_database As d where datname = current_database()),+| |
- (SELECT s.queryid FROM pg_stat_statements AS s +| |
- WHERE s.query = $2 LIMIT $3)) | |
- SELECT pg_stat_statements_reset($1) | 1 | 1
- SELECT pg_stat_statements_reset($1,$2,s.queryid) +| 1 | 2
- FROM pg_stat_statements AS s WHERE s.query = $3 | |
- SELECT pg_stat_statements_reset() | 1 | 1
- SELECT pg_stat_statements_reset(r.oid) +| 1 | 1
- FROM pg_roles AS r WHERE r.rolname = $1 | |
- SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 4 | 46
- SET ROLE regress_stats_user2 | 1 | 0
-(10 rows)
-
---
--- reset all
---
-SELECT pg_stat_statements_reset(0,0,0);
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
- query | calls | rows
-------------------------------------------------------------------------------+-------+------
- SELECT pg_stat_statements_reset(0,0,0) | 1 | 1
- SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 0 | 0
-(2 rows)
-
---
--- cleanup
---
-DROP ROLE regress_stats_user1;
-DROP ROLE regress_stats_user2;
---
--- access to pg_stat_statements_info view
---
-SELECT pg_stat_statements_reset();
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
-SELECT dealloc FROM pg_stat_statements_info;
- dealloc
----------
- 0
-(1 row)
-
--- FROM [ONLY]
-CREATE TABLE tbl_inh(id integer);
-CREATE TABLE tbl_inh_1() INHERITS (tbl_inh);
-INSERT INTO tbl_inh_1 SELECT 1;
-SELECT * FROM tbl_inh;
- id
-----
- 1
-(1 row)
-
-SELECT * FROM ONLY tbl_inh;
- id
-----
-(0 rows)
-
-SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%FROM%tbl_inh%';
- count
--------
- 2
-(1 row)
-
--- WITH TIES
-CREATE TABLE limitoption AS SELECT 0 AS val FROM generate_series(1, 10);
-SELECT *
-FROM limitoption
-WHERE val < 2
-ORDER BY val
-FETCH FIRST 2 ROWS WITH TIES;
- val
------
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
-(10 rows)
-
-SELECT *
-FROM limitoption
-WHERE val < 2
-ORDER BY val
-FETCH FIRST 2 ROW ONLY;
- val
------
- 0
- 0
-(2 rows)
-
-SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%FETCH FIRST%';
- count
--------
- 2
-(1 row)
-
--- GROUP BY [DISTINCT]
-SELECT a, b, c
-FROM (VALUES (1, 2, 3), (4, NULL, 6), (7, 8, 9)) AS t (a, b, c)
-GROUP BY ROLLUP(a, b), rollup(a, c)
-ORDER BY a, b, c;
- a | b | c
----+---+---
- 1 | 2 | 3
- 1 | 2 |
- 1 | 2 |
- 1 | | 3
- 1 | | 3
- 1 | |
- 1 | |
- 1 | |
- 4 | | 6
- 4 | | 6
- 4 | | 6
- 4 | |
- 4 | |
- 4 | |
- 4 | |
- 4 | |
- 7 | 8 | 9
- 7 | 8 |
- 7 | 8 |
- 7 | | 9
- 7 | | 9
- 7 | |
- 7 | |
- 7 | |
- | |
-(25 rows)
-
-SELECT a, b, c
-FROM (VALUES (1, 2, 3), (4, NULL, 6), (7, 8, 9)) AS t (a, b, c)
-GROUP BY DISTINCT ROLLUP(a, b), rollup(a, c)
-ORDER BY a, b, c;
- a | b | c
----+---+---
- 1 | 2 | 3
- 1 | 2 |
- 1 | | 3
- 1 | |
- 4 | | 6
- 4 | | 6
- 4 | |
- 4 | |
- 7 | 8 | 9
- 7 | 8 |
- 7 | | 9
- 7 | |
- | |
-(13 rows)
-
-SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%GROUP BY%ROLLUP%';
- count
--------
- 2
-(1 row)
-
--- GROUPING SET agglevelsup
-SELECT (
- SELECT (
- SELECT GROUPING(a,b) FROM (VALUES (1)) v2(c)
- ) FROM (VALUES (1,2)) v1(a,b) GROUP BY (a,b)
-) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
- grouping
-----------
- 0
- 0
- 0
-(3 rows)
-
-SELECT (
- SELECT (
- SELECT GROUPING(e,f) FROM (VALUES (1)) v2(c)
- ) FROM (VALUES (1,2)) v1(a,b) GROUP BY (a,b)
-) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
- grouping
-----------
- 3
- 0
- 1
-(3 rows)
-
-SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%SELECT GROUPING%';
- count
--------
- 2
-(1 row)
-
diff --git a/contrib/pg_stat_statements/expected/select.out b/contrib/pg_stat_statements/expected/select.out
new file mode 100644
index 0000000000..972539b2c5
--- /dev/null
+++ b/contrib/pg_stat_statements/expected/select.out
@@ -0,0 +1,414 @@
+--
+-- SELECT statements
+--
+CREATE EXTENSION pg_stat_statements;
+SET pg_stat_statements.track_utility = FALSE;
+SET pg_stat_statements.track_planning = TRUE;
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+--
+-- simple and compound statements
+--
+SELECT 1 AS "int";
+ int
+-----
+ 1
+(1 row)
+
+SELECT 'hello'
+ -- multiline
+ AS "text";
+ text
+-------
+ hello
+(1 row)
+
+SELECT 'world' AS "text";
+ text
+-------
+ world
+(1 row)
+
+-- transaction
+BEGIN;
+SELECT 1 AS "int";
+ int
+-----
+ 1
+(1 row)
+
+SELECT 'hello' AS "text";
+ text
+-------
+ hello
+(1 row)
+
+COMMIT;
+-- compound transaction
+BEGIN \;
+SELECT 2.0 AS "float" \;
+SELECT 'world' AS "text" \;
+COMMIT;
+ float
+-------
+ 2.0
+(1 row)
+
+ text
+-------
+ world
+(1 row)
+
+-- compound with empty statements and spurious leading spacing
+\;\; SELECT 3 + 3 \;\;\; SELECT ' ' || ' !' \;\; SELECT 1 + 4 \;;
+ ?column?
+----------
+ 6
+(1 row)
+
+ ?column?
+----------
+ !
+(1 row)
+
+ ?column?
+----------
+ 5
+(1 row)
+
+-- non ;-terminated statements
+SELECT 1 + 1 + 1 AS "add" \gset
+SELECT :add + 1 + 1 AS "add" \;
+SELECT :add + 1 + 1 AS "add" \gset
+ add
+-----
+ 5
+(1 row)
+
+-- set operator
+SELECT 1 AS i UNION SELECT 2 ORDER BY i;
+ i
+---
+ 1
+ 2
+(2 rows)
+
+-- ? operator
+select '{"a":1, "b":2}'::jsonb ? 'b';
+ ?column?
+----------
+ t
+(1 row)
+
+-- cte
+WITH t(f) AS (
+ VALUES (1.0), (2.0)
+)
+ SELECT f FROM t ORDER BY f;
+ f
+-----
+ 1.0
+ 2.0
+(2 rows)
+
+-- prepared statement with parameter
+PREPARE pgss_test (int) AS SELECT $1, 'test' LIMIT 1;
+EXECUTE pgss_test(1);
+ ?column? | ?column?
+----------+----------
+ 1 | test
+(1 row)
+
+DEALLOCATE pgss_test;
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+ calls | rows | query
+-------+------+------------------------------------------------------------------------------
+ 1 | 1 | PREPARE pgss_test (int) AS SELECT $1, $2 LIMIT $3
+ 4 | 4 | SELECT $1 +
+ | | -- multiline +
+ | | AS "text"
+ 2 | 2 | SELECT $1 + $2
+ 3 | 3 | SELECT $1 + $2 + $3 AS "add"
+ 1 | 1 | SELECT $1 AS "float"
+ 2 | 2 | SELECT $1 AS "int"
+ 1 | 2 | SELECT $1 AS i UNION SELECT $2 ORDER BY i
+ 1 | 1 | SELECT $1 || $2
+ 0 | 0 | SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C"
+ 1 | 1 | SELECT pg_stat_statements_reset()
+ 1 | 2 | WITH t(f) AS ( +
+ | | VALUES ($1), ($2) +
+ | | ) +
+ | | SELECT f FROM t ORDER BY f
+ 1 | 1 | select $1::jsonb ? $2
+(12 rows)
+
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+--
+-- queries with locking clauses
+--
+CREATE TABLE pgss_a (id integer PRIMARY KEY);
+CREATE TABLE pgss_b (id integer PRIMARY KEY, a_id integer REFERENCES pgss_a);
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+-- control query
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id;
+ id | id | a_id
+----+----+------
+(0 rows)
+
+-- test range tables
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE;
+ id | id | a_id
+----+----+------
+(0 rows)
+
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a;
+ id | id | a_id
+----+----+------
+(0 rows)
+
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b;
+ id | id | a_id
+----+----+------
+(0 rows)
+
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a, pgss_b; -- matches plain "FOR UPDATE"
+ id | id | a_id
+----+----+------
+(0 rows)
+
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b, pgss_a;
+ id | id | a_id
+----+----+------
+(0 rows)
+
+-- test strengths
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR NO KEY UPDATE;
+ id | id | a_id
+----+----+------
+(0 rows)
+
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR SHARE;
+ id | id | a_id
+----+----+------
+(0 rows)
+
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR KEY SHARE;
+ id | id | a_id
+----+----+------
+(0 rows)
+
+-- test wait policies
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE NOWAIT;
+ id | id | a_id
+----+----+------
+(0 rows)
+
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE SKIP LOCKED;
+ id | id | a_id
+----+----+------
+(0 rows)
+
+SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+ calls | query
+-------+------------------------------------------------------------------------------------------
+ 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id
+ 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR KEY SHARE
+ 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR NO KEY UPDATE
+ 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR SHARE
+ 2 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE
+ 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE NOWAIT
+ 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a
+ 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b
+ 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b, pgss_a
+ 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE SKIP LOCKED
+ 0 | SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C"
+ 1 | SELECT pg_stat_statements_reset()
+(12 rows)
+
+DROP TABLE pgss_a, pgss_b CASCADE;
+--
+-- access to pg_stat_statements_info view
+--
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+SELECT dealloc FROM pg_stat_statements_info;
+ dealloc
+---------
+ 0
+(1 row)
+
+-- FROM [ONLY]
+CREATE TABLE tbl_inh(id integer);
+CREATE TABLE tbl_inh_1() INHERITS (tbl_inh);
+INSERT INTO tbl_inh_1 SELECT 1;
+SELECT * FROM tbl_inh;
+ id
+----
+ 1
+(1 row)
+
+SELECT * FROM ONLY tbl_inh;
+ id
+----
+(0 rows)
+
+SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%FROM%tbl_inh%';
+ count
+-------
+ 2
+(1 row)
+
+-- WITH TIES
+CREATE TABLE limitoption AS SELECT 0 AS val FROM generate_series(1, 10);
+SELECT *
+FROM limitoption
+WHERE val < 2
+ORDER BY val
+FETCH FIRST 2 ROWS WITH TIES;
+ val
+-----
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+(10 rows)
+
+SELECT *
+FROM limitoption
+WHERE val < 2
+ORDER BY val
+FETCH FIRST 2 ROW ONLY;
+ val
+-----
+ 0
+ 0
+(2 rows)
+
+SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%FETCH FIRST%';
+ count
+-------
+ 2
+(1 row)
+
+-- GROUP BY [DISTINCT]
+SELECT a, b, c
+FROM (VALUES (1, 2, 3), (4, NULL, 6), (7, 8, 9)) AS t (a, b, c)
+GROUP BY ROLLUP(a, b), rollup(a, c)
+ORDER BY a, b, c;
+ a | b | c
+---+---+---
+ 1 | 2 | 3
+ 1 | 2 |
+ 1 | 2 |
+ 1 | | 3
+ 1 | | 3
+ 1 | |
+ 1 | |
+ 1 | |
+ 4 | | 6
+ 4 | | 6
+ 4 | | 6
+ 4 | |
+ 4 | |
+ 4 | |
+ 4 | |
+ 4 | |
+ 7 | 8 | 9
+ 7 | 8 |
+ 7 | 8 |
+ 7 | | 9
+ 7 | | 9
+ 7 | |
+ 7 | |
+ 7 | |
+ | |
+(25 rows)
+
+SELECT a, b, c
+FROM (VALUES (1, 2, 3), (4, NULL, 6), (7, 8, 9)) AS t (a, b, c)
+GROUP BY DISTINCT ROLLUP(a, b), rollup(a, c)
+ORDER BY a, b, c;
+ a | b | c
+---+---+---
+ 1 | 2 | 3
+ 1 | 2 |
+ 1 | | 3
+ 1 | |
+ 4 | | 6
+ 4 | | 6
+ 4 | |
+ 4 | |
+ 7 | 8 | 9
+ 7 | 8 |
+ 7 | | 9
+ 7 | |
+ | |
+(13 rows)
+
+SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%GROUP BY%ROLLUP%';
+ count
+-------
+ 2
+(1 row)
+
+-- GROUPING SET agglevelsup
+SELECT (
+ SELECT (
+ SELECT GROUPING(a,b) FROM (VALUES (1)) v2(c)
+ ) FROM (VALUES (1,2)) v1(a,b) GROUP BY (a,b)
+) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
+ grouping
+----------
+ 0
+ 0
+ 0
+(3 rows)
+
+SELECT (
+ SELECT (
+ SELECT GROUPING(e,f) FROM (VALUES (1)) v2(c)
+ ) FROM (VALUES (1,2)) v1(a,b) GROUP BY (a,b)
+) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
+ grouping
+----------
+ 3
+ 0
+ 1
+(3 rows)
+
+SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%SELECT GROUPING%';
+ count
+-------
+ 2
+(1 row)
+
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
diff --git a/contrib/pg_stat_statements/expected/user_activity.out b/contrib/pg_stat_statements/expected/user_activity.out
new file mode 100644
index 0000000000..f06e5881e5
--- /dev/null
+++ b/contrib/pg_stat_statements/expected/user_activity.out
@@ -0,0 +1,199 @@
+--
+-- Track user activity and reset them
+--
+SET pg_stat_statements.track_utility = TRUE;
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+CREATE ROLE regress_stats_user1;
+CREATE ROLE regress_stats_user2;
+SET ROLE regress_stats_user1;
+SELECT 1 AS "ONE";
+ ONE
+-----
+ 1
+(1 row)
+
+SELECT 1+1 AS "TWO";
+ TWO
+-----
+ 2
+(1 row)
+
+RESET ROLE;
+SET ROLE regress_stats_user2;
+SELECT 1 AS "ONE";
+ ONE
+-----
+ 1
+(1 row)
+
+SELECT 1+1 AS "TWO";
+ TWO
+-----
+ 2
+(1 row)
+
+RESET ROLE;
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
+ query | calls | rows
+-----------------------------------+-------+------
+ CREATE ROLE regress_stats_user1 | 1 | 0
+ CREATE ROLE regress_stats_user2 | 1 | 0
+ RESET ROLE | 2 | 0
+ SELECT $1 AS "ONE" | 1 | 1
+ SELECT $1 AS "ONE" | 1 | 1
+ SELECT $1+$2 AS "TWO" | 1 | 1
+ SELECT $1+$2 AS "TWO" | 1 | 1
+ SELECT pg_stat_statements_reset() | 1 | 1
+ SET ROLE regress_stats_user1 | 1 | 0
+ SET ROLE regress_stats_user2 | 1 | 0
+(10 rows)
+
+--
+-- Don't reset anything if any of the parameter is NULL
+--
+SELECT pg_stat_statements_reset(NULL);
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
+ query | calls | rows
+------------------------------------------------------------------------------+-------+------
+ CREATE ROLE regress_stats_user1 | 1 | 0
+ CREATE ROLE regress_stats_user2 | 1 | 0
+ RESET ROLE | 2 | 0
+ SELECT $1 AS "ONE" | 1 | 1
+ SELECT $1 AS "ONE" | 1 | 1
+ SELECT $1+$2 AS "TWO" | 1 | 1
+ SELECT $1+$2 AS "TWO" | 1 | 1
+ SELECT pg_stat_statements_reset($1) | 1 | 1
+ SELECT pg_stat_statements_reset() | 1 | 1
+ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 1 | 10
+ SET ROLE regress_stats_user1 | 1 | 0
+ SET ROLE regress_stats_user2 | 1 | 0
+(12 rows)
+
+--
+-- remove query ('SELECT $1+$2 AS "TWO"') executed by regress_stats_user2
+-- in the current_database
+--
+SELECT pg_stat_statements_reset(
+ (SELECT r.oid FROM pg_roles AS r WHERE r.rolname = 'regress_stats_user2'),
+ (SELECT d.oid FROM pg_database As d where datname = current_database()),
+ (SELECT s.queryid FROM pg_stat_statements AS s
+ WHERE s.query = 'SELECT $1+$2 AS "TWO"' LIMIT 1));
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
+ query | calls | rows
+----------------------------------------------------------------------------------+-------+------
+ CREATE ROLE regress_stats_user1 | 1 | 0
+ CREATE ROLE regress_stats_user2 | 1 | 0
+ RESET ROLE | 2 | 0
+ SELECT $1 AS "ONE" | 1 | 1
+ SELECT $1 AS "ONE" | 1 | 1
+ SELECT $1+$2 AS "TWO" | 1 | 1
+ SELECT pg_stat_statements_reset( +| 1 | 1
+ (SELECT r.oid FROM pg_roles AS r WHERE r.rolname = $1), +| |
+ (SELECT d.oid FROM pg_database As d where datname = current_database()),+| |
+ (SELECT s.queryid FROM pg_stat_statements AS s +| |
+ WHERE s.query = $2 LIMIT $3)) | |
+ SELECT pg_stat_statements_reset($1) | 1 | 1
+ SELECT pg_stat_statements_reset() | 1 | 1
+ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 2 | 22
+ SET ROLE regress_stats_user1 | 1 | 0
+ SET ROLE regress_stats_user2 | 1 | 0
+(12 rows)
+
+--
+-- remove query ('SELECT $1 AS "ONE"') executed by two users
+--
+SELECT pg_stat_statements_reset(0,0,s.queryid)
+ FROM pg_stat_statements AS s WHERE s.query = 'SELECT $1 AS "ONE"';
+ pg_stat_statements_reset
+--------------------------
+
+
+(2 rows)
+
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
+ query | calls | rows
+----------------------------------------------------------------------------------+-------+------
+ CREATE ROLE regress_stats_user1 | 1 | 0
+ CREATE ROLE regress_stats_user2 | 1 | 0
+ RESET ROLE | 2 | 0
+ SELECT $1+$2 AS "TWO" | 1 | 1
+ SELECT pg_stat_statements_reset( +| 1 | 1
+ (SELECT r.oid FROM pg_roles AS r WHERE r.rolname = $1), +| |
+ (SELECT d.oid FROM pg_database As d where datname = current_database()),+| |
+ (SELECT s.queryid FROM pg_stat_statements AS s +| |
+ WHERE s.query = $2 LIMIT $3)) | |
+ SELECT pg_stat_statements_reset($1) | 1 | 1
+ SELECT pg_stat_statements_reset($1,$2,s.queryid) +| 1 | 2
+ FROM pg_stat_statements AS s WHERE s.query = $3 | |
+ SELECT pg_stat_statements_reset() | 1 | 1
+ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 3 | 34
+ SET ROLE regress_stats_user1 | 1 | 0
+ SET ROLE regress_stats_user2 | 1 | 0
+(11 rows)
+
+--
+-- remove query of a user (regress_stats_user1)
+--
+SELECT pg_stat_statements_reset(r.oid)
+ FROM pg_roles AS r WHERE r.rolname = 'regress_stats_user1';
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
+ query | calls | rows
+----------------------------------------------------------------------------------+-------+------
+ CREATE ROLE regress_stats_user1 | 1 | 0
+ CREATE ROLE regress_stats_user2 | 1 | 0
+ RESET ROLE | 2 | 0
+ SELECT pg_stat_statements_reset( +| 1 | 1
+ (SELECT r.oid FROM pg_roles AS r WHERE r.rolname = $1), +| |
+ (SELECT d.oid FROM pg_database As d where datname = current_database()),+| |
+ (SELECT s.queryid FROM pg_stat_statements AS s +| |
+ WHERE s.query = $2 LIMIT $3)) | |
+ SELECT pg_stat_statements_reset($1) | 1 | 1
+ SELECT pg_stat_statements_reset($1,$2,s.queryid) +| 1 | 2
+ FROM pg_stat_statements AS s WHERE s.query = $3 | |
+ SELECT pg_stat_statements_reset() | 1 | 1
+ SELECT pg_stat_statements_reset(r.oid) +| 1 | 1
+ FROM pg_roles AS r WHERE r.rolname = $1 | |
+ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 4 | 45
+ SET ROLE regress_stats_user2 | 1 | 0
+(10 rows)
+
+--
+-- reset all
+--
+SELECT pg_stat_statements_reset(0,0,0);
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
+ query | calls | rows
+----------------------------------------+-------+------
+ SELECT pg_stat_statements_reset(0,0,0) | 1 | 1
+(1 row)
+
+--
+-- cleanup
+--
+DROP ROLE regress_stats_user1;
+DROP ROLE regress_stats_user2;
diff --git a/contrib/pg_stat_statements/expected/wal.out b/contrib/pg_stat_statements/expected/wal.out
new file mode 100644
index 0000000000..f115fa0d5b
--- /dev/null
+++ b/contrib/pg_stat_statements/expected/wal.out
@@ -0,0 +1,33 @@
+--
+-- Validate WAL generation metrics
+--
+SET pg_stat_statements.track_utility = FALSE;
+CREATE TABLE pgss_wal_tab (a int, b char(20));
+INSERT INTO pgss_wal_tab VALUES(generate_series(1, 10), 'aaa');
+UPDATE pgss_wal_tab SET b = 'bbb' WHERE a > 7;
+DELETE FROM pgss_wal_tab WHERE a > 9;
+DROP TABLE pgss_wal_tab;
+-- Check WAL is generated for the above statements
+SELECT query, calls, rows,
+wal_bytes > 0 as wal_bytes_generated,
+wal_records > 0 as wal_records_generated,
+wal_records >= rows as wal_records_ge_rows
+FROM pg_stat_statements ORDER BY query COLLATE "C";
+ query | calls | rows | wal_bytes_generated | wal_records_generated | wal_records_ge_rows
+------------------------------------------------------------------------------+-------+------+---------------------+-----------------------+---------------------
+ DELETE FROM pgss_wal_tab WHERE a > $1 | 1 | 1 | t | t | t
+ DROP ROLE regress_stats_user1 | 1 | 0 | t | t | t
+ DROP ROLE regress_stats_user2 | 1 | 0 | t | t | t
+ INSERT INTO pgss_wal_tab VALUES(generate_series($1, $2), $3) | 1 | 10 | t | t | t
+ SELECT pg_stat_statements_reset(0,0,0) | 1 | 1 | f | f | f
+ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 1 | 1 | f | f | f
+ SET pg_stat_statements.track_utility = FALSE | 1 | 0 | f | f | t
+ UPDATE pgss_wal_tab SET b = $1 WHERE a > $2 | 1 | 3 | t | t | t
+(8 rows)
+
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
diff --git a/contrib/pg_stat_statements/meson.build b/contrib/pg_stat_statements/meson.build
index 10ccc26300..3e3062ada9 100644
--- a/contrib/pg_stat_statements/meson.build
+++ b/contrib/pg_stat_statements/meson.build
@@ -40,11 +40,14 @@ tests += {
'bd': meson.current_build_dir(),
'regress': {
'sql': [
- 'pg_stat_statements',
+ 'select',
+ 'dml',
'cursors',
'utility',
'level_tracking',
'planning',
+ 'user_activity',
+ 'wal',
'cleanup',
'oldextversions',
],
diff --git a/contrib/pg_stat_statements/sql/dml.sql b/contrib/pg_stat_statements/sql/dml.sql
new file mode 100644
index 0000000000..af2f9fcf73
--- /dev/null
+++ b/contrib/pg_stat_statements/sql/dml.sql
@@ -0,0 +1,76 @@
+--
+-- DMLs on test table
+--
+
+SET pg_stat_statements.track_utility = FALSE;
+
+CREATE TEMP TABLE pgss_dml_tab (a int, b char(20));
+
+INSERT INTO pgss_dml_tab VALUES(generate_series(1, 10), 'aaa');
+UPDATE pgss_dml_tab SET b = 'bbb' WHERE a > 7;
+DELETE FROM pgss_dml_tab WHERE a > 9;
+
+-- explicit transaction
+BEGIN;
+UPDATE pgss_dml_tab SET b = '111' WHERE a = 1 ;
+COMMIT;
+
+BEGIN \;
+UPDATE pgss_dml_tab SET b = '222' WHERE a = 2 \;
+COMMIT ;
+
+UPDATE pgss_dml_tab SET b = '333' WHERE a = 3 \;
+UPDATE pgss_dml_tab SET b = '444' WHERE a = 4 ;
+
+BEGIN \;
+UPDATE pgss_dml_tab SET b = '555' WHERE a = 5 \;
+UPDATE pgss_dml_tab SET b = '666' WHERE a = 6 \;
+COMMIT ;
+
+-- many INSERT values
+INSERT INTO pgss_dml_tab (a, b) VALUES (1, 'a'), (2, 'b'), (3, 'c');
+
+-- SELECT with constants
+SELECT * FROM pgss_dml_tab WHERE a > 5 ORDER BY a ;
+
+SELECT *
+ FROM pgss_dml_tab
+ WHERE a > 9
+ ORDER BY a ;
+
+-- these two need to be done on a different table
+-- SELECT without constants
+SELECT * FROM pgss_dml_tab ORDER BY a;
+
+-- SELECT with IN clause
+SELECT * FROM pgss_dml_tab WHERE a IN (1, 2, 3, 4, 5);
+
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+SELECT pg_stat_statements_reset();
+
+-- MERGE
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= 4)
+ WHEN MATCHED THEN UPDATE SET b = st.b || st.a::text;
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= 4)
+ WHEN MATCHED THEN UPDATE SET b = pgss_dml_tab.b || st.a::text;
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= 4)
+ WHEN MATCHED AND length(st.b) > 1 THEN UPDATE SET b = pgss_dml_tab.b || st.a::text;
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a)
+ WHEN NOT MATCHED THEN INSERT (a, b) VALUES (0, NULL);
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a)
+ WHEN NOT MATCHED THEN INSERT VALUES (0, NULL); -- same as above
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a)
+ WHEN NOT MATCHED THEN INSERT (b, a) VALUES (NULL, 0);
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a)
+ WHEN NOT MATCHED THEN INSERT (a) VALUES (0);
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= 4)
+ WHEN MATCHED THEN DELETE;
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= 4)
+ WHEN MATCHED THEN DO NOTHING;
+MERGE INTO pgss_dml_tab USING pgss_dml_tab st ON (st.a = pgss_dml_tab.a AND st.a >= 4)
+ WHEN NOT MATCHED THEN DO NOTHING;
+
+DROP TABLE pgss_dml_tab;
+
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+SELECT pg_stat_statements_reset();
diff --git a/contrib/pg_stat_statements/sql/pg_stat_statements.sql b/contrib/pg_stat_statements/sql/pg_stat_statements.sql
deleted file mode 100644
index 3a3d235066..0000000000
--- a/contrib/pg_stat_statements/sql/pg_stat_statements.sql
+++ /dev/null
@@ -1,300 +0,0 @@
-CREATE EXTENSION pg_stat_statements;
-
---
--- simple and compound statements
---
-SET pg_stat_statements.track_utility = FALSE;
-SET pg_stat_statements.track_planning = TRUE;
-SELECT pg_stat_statements_reset();
-
-SELECT 1 AS "int";
-
-SELECT 'hello'
- -- multiline
- AS "text";
-
-SELECT 'world' AS "text";
-
--- transaction
-BEGIN;
-SELECT 1 AS "int";
-SELECT 'hello' AS "text";
-COMMIT;
-
--- compound transaction
-BEGIN \;
-SELECT 2.0 AS "float" \;
-SELECT 'world' AS "text" \;
-COMMIT;
-
--- compound with empty statements and spurious leading spacing
-\;\; SELECT 3 + 3 \;\;\; SELECT ' ' || ' !' \;\; SELECT 1 + 4 \;;
-
--- non ;-terminated statements
-SELECT 1 + 1 + 1 AS "add" \gset
-SELECT :add + 1 + 1 AS "add" \;
-SELECT :add + 1 + 1 AS "add" \gset
-
--- set operator
-SELECT 1 AS i UNION SELECT 2 ORDER BY i;
-
--- ? operator
-select '{"a":1, "b":2}'::jsonb ? 'b';
-
--- cte
-WITH t(f) AS (
- VALUES (1.0), (2.0)
-)
- SELECT f FROM t ORDER BY f;
-
--- prepared statement with parameter
-PREPARE pgss_test (int) AS SELECT $1, 'test' LIMIT 1;
-EXECUTE pgss_test(1);
-DEALLOCATE pgss_test;
-
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-
---
--- CRUD: INSERT SELECT UPDATE DELETE on test table
---
-SELECT pg_stat_statements_reset();
-
--- utility "create table" should not be shown
-CREATE TEMP TABLE test (a int, b char(20));
-
-INSERT INTO test VALUES(generate_series(1, 10), 'aaa');
-UPDATE test SET b = 'bbb' WHERE a > 7;
-DELETE FROM test WHERE a > 9;
-
--- explicit transaction
-BEGIN;
-UPDATE test SET b = '111' WHERE a = 1 ;
-COMMIT;
-
-BEGIN \;
-UPDATE test SET b = '222' WHERE a = 2 \;
-COMMIT ;
-
-UPDATE test SET b = '333' WHERE a = 3 \;
-UPDATE test SET b = '444' WHERE a = 4 ;
-
-BEGIN \;
-UPDATE test SET b = '555' WHERE a = 5 \;
-UPDATE test SET b = '666' WHERE a = 6 \;
-COMMIT ;
-
--- many INSERT values
-INSERT INTO test (a, b) VALUES (1, 'a'), (2, 'b'), (3, 'c');
-
--- SELECT with constants
-SELECT * FROM test WHERE a > 5 ORDER BY a ;
-
-SELECT *
- FROM test
- WHERE a > 9
- ORDER BY a ;
-
--- SELECT without constants
-SELECT * FROM test ORDER BY a;
-
--- SELECT with IN clause
-SELECT * FROM test WHERE a IN (1, 2, 3, 4, 5);
-
--- MERGE
-MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4)
- WHEN MATCHED THEN UPDATE SET b = st.b || st.a::text;
-MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4)
- WHEN MATCHED THEN UPDATE SET b = test.b || st.a::text;
-MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4)
- WHEN MATCHED AND length(st.b) > 1 THEN UPDATE SET b = test.b || st.a::text;
-MERGE INTO test USING test st ON (st.a = test.a)
- WHEN NOT MATCHED THEN INSERT (a, b) VALUES (0, NULL);
-MERGE INTO test USING test st ON (st.a = test.a)
- WHEN NOT MATCHED THEN INSERT VALUES (0, NULL); -- same as above
-MERGE INTO test USING test st ON (st.a = test.a)
- WHEN NOT MATCHED THEN INSERT (b, a) VALUES (NULL, 0);
-MERGE INTO test USING test st ON (st.a = test.a)
- WHEN NOT MATCHED THEN INSERT (a) VALUES (0);
-MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4)
- WHEN MATCHED THEN DELETE;
-MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4)
- WHEN MATCHED THEN DO NOTHING;
-MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4)
- WHEN NOT MATCHED THEN DO NOTHING;
-
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-
---
--- INSERT, UPDATE, DELETE on test table to validate WAL generation metrics
---
-SELECT pg_stat_statements_reset();
-
--- utility "create table" should not be shown
-CREATE TABLE pgss_test (a int, b char(20));
-
-INSERT INTO pgss_test VALUES(generate_series(1, 10), 'aaa');
-UPDATE pgss_test SET b = 'bbb' WHERE a > 7;
-DELETE FROM pgss_test WHERE a > 9;
--- DROP test table
-DROP TABLE pgss_test;
-
--- Check WAL is generated for the above statements
-SELECT query, calls, rows,
-wal_bytes > 0 as wal_bytes_generated,
-wal_records > 0 as wal_records_generated,
-wal_records >= rows as wal_records_ge_rows
-FROM pg_stat_statements ORDER BY query COLLATE "C";
-
---
--- queries with locking clauses
---
-CREATE TABLE pgss_a (id integer PRIMARY KEY);
-CREATE TABLE pgss_b (id integer PRIMARY KEY, a_id integer REFERENCES pgss_a);
-
-SELECT pg_stat_statements_reset();
-
--- control query
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id;
-
--- test range tables
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE;
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a;
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b;
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a, pgss_b; -- matches plain "FOR UPDATE"
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b, pgss_a;
-
--- test strengths
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR NO KEY UPDATE;
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR SHARE;
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR KEY SHARE;
-
--- test wait policies
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE NOWAIT;
-SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE SKIP LOCKED;
-
-SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C";
-
-DROP TABLE pgss_a, pgss_b CASCADE;
-
---
--- Track user activity and reset them
---
-SET pg_stat_statements.track_utility = TRUE;
-SELECT pg_stat_statements_reset();
-CREATE ROLE regress_stats_user1;
-CREATE ROLE regress_stats_user2;
-
-SET ROLE regress_stats_user1;
-
-SELECT 1 AS "ONE";
-SELECT 1+1 AS "TWO";
-
-RESET ROLE;
-SET ROLE regress_stats_user2;
-
-SELECT 1 AS "ONE";
-SELECT 1+1 AS "TWO";
-
-RESET ROLE;
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-
---
--- Don't reset anything if any of the parameter is NULL
---
-SELECT pg_stat_statements_reset(NULL);
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-
---
--- remove query ('SELECT $1+$2 AS "TWO"') executed by regress_stats_user2
--- in the current_database
---
-SELECT pg_stat_statements_reset(
- (SELECT r.oid FROM pg_roles AS r WHERE r.rolname = 'regress_stats_user2'),
- (SELECT d.oid FROM pg_database As d where datname = current_database()),
- (SELECT s.queryid FROM pg_stat_statements AS s
- WHERE s.query = 'SELECT $1+$2 AS "TWO"' LIMIT 1));
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-
---
--- remove query ('SELECT $1 AS "ONE"') executed by two users
---
-SELECT pg_stat_statements_reset(0,0,s.queryid)
- FROM pg_stat_statements AS s WHERE s.query = 'SELECT $1 AS "ONE"';
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-
---
--- remove query of a user (regress_stats_user1)
---
-SELECT pg_stat_statements_reset(r.oid)
- FROM pg_roles AS r WHERE r.rolname = 'regress_stats_user1';
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-
---
--- reset all
---
-SELECT pg_stat_statements_reset(0,0,0);
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-
---
--- cleanup
---
-DROP ROLE regress_stats_user1;
-DROP ROLE regress_stats_user2;
-
---
--- access to pg_stat_statements_info view
---
-SELECT pg_stat_statements_reset();
-SELECT dealloc FROM pg_stat_statements_info;
-
--- FROM [ONLY]
-CREATE TABLE tbl_inh(id integer);
-CREATE TABLE tbl_inh_1() INHERITS (tbl_inh);
-INSERT INTO tbl_inh_1 SELECT 1;
-
-SELECT * FROM tbl_inh;
-SELECT * FROM ONLY tbl_inh;
-
-SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%FROM%tbl_inh%';
-
--- WITH TIES
-CREATE TABLE limitoption AS SELECT 0 AS val FROM generate_series(1, 10);
-SELECT *
-FROM limitoption
-WHERE val < 2
-ORDER BY val
-FETCH FIRST 2 ROWS WITH TIES;
-
-SELECT *
-FROM limitoption
-WHERE val < 2
-ORDER BY val
-FETCH FIRST 2 ROW ONLY;
-
-SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%FETCH FIRST%';
-
--- GROUP BY [DISTINCT]
-SELECT a, b, c
-FROM (VALUES (1, 2, 3), (4, NULL, 6), (7, 8, 9)) AS t (a, b, c)
-GROUP BY ROLLUP(a, b), rollup(a, c)
-ORDER BY a, b, c;
-SELECT a, b, c
-FROM (VALUES (1, 2, 3), (4, NULL, 6), (7, 8, 9)) AS t (a, b, c)
-GROUP BY DISTINCT ROLLUP(a, b), rollup(a, c)
-ORDER BY a, b, c;
-
-SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%GROUP BY%ROLLUP%';
-
--- GROUPING SET agglevelsup
-SELECT (
- SELECT (
- SELECT GROUPING(a,b) FROM (VALUES (1)) v2(c)
- ) FROM (VALUES (1,2)) v1(a,b) GROUP BY (a,b)
-) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
-SELECT (
- SELECT (
- SELECT GROUPING(e,f) FROM (VALUES (1)) v2(c)
- ) FROM (VALUES (1,2)) v1(a,b) GROUP BY (a,b)
-) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
-
-SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%SELECT GROUPING%';
diff --git a/contrib/pg_stat_statements/sql/select.sql b/contrib/pg_stat_statements/sql/select.sql
new file mode 100644
index 0000000000..eef7b0bbf5
--- /dev/null
+++ b/contrib/pg_stat_statements/sql/select.sql
@@ -0,0 +1,149 @@
+--
+-- SELECT statements
+--
+
+CREATE EXTENSION pg_stat_statements;
+SET pg_stat_statements.track_utility = FALSE;
+SET pg_stat_statements.track_planning = TRUE;
+SELECT pg_stat_statements_reset();
+
+--
+-- simple and compound statements
+--
+SELECT 1 AS "int";
+
+SELECT 'hello'
+ -- multiline
+ AS "text";
+
+SELECT 'world' AS "text";
+
+-- transaction
+BEGIN;
+SELECT 1 AS "int";
+SELECT 'hello' AS "text";
+COMMIT;
+
+-- compound transaction
+BEGIN \;
+SELECT 2.0 AS "float" \;
+SELECT 'world' AS "text" \;
+COMMIT;
+
+-- compound with empty statements and spurious leading spacing
+\;\; SELECT 3 + 3 \;\;\; SELECT ' ' || ' !' \;\; SELECT 1 + 4 \;;
+
+-- non ;-terminated statements
+SELECT 1 + 1 + 1 AS "add" \gset
+SELECT :add + 1 + 1 AS "add" \;
+SELECT :add + 1 + 1 AS "add" \gset
+
+-- set operator
+SELECT 1 AS i UNION SELECT 2 ORDER BY i;
+
+-- ? operator
+select '{"a":1, "b":2}'::jsonb ? 'b';
+
+-- cte
+WITH t(f) AS (
+ VALUES (1.0), (2.0)
+)
+ SELECT f FROM t ORDER BY f;
+
+-- prepared statement with parameter
+PREPARE pgss_test (int) AS SELECT $1, 'test' LIMIT 1;
+EXECUTE pgss_test(1);
+DEALLOCATE pgss_test;
+
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+SELECT pg_stat_statements_reset();
+
+--
+-- queries with locking clauses
+--
+CREATE TABLE pgss_a (id integer PRIMARY KEY);
+CREATE TABLE pgss_b (id integer PRIMARY KEY, a_id integer REFERENCES pgss_a);
+
+SELECT pg_stat_statements_reset();
+
+-- control query
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id;
+
+-- test range tables
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE;
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a;
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b;
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a, pgss_b; -- matches plain "FOR UPDATE"
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b, pgss_a;
+
+-- test strengths
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR NO KEY UPDATE;
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR SHARE;
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR KEY SHARE;
+
+-- test wait policies
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE NOWAIT;
+SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE SKIP LOCKED;
+
+SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+DROP TABLE pgss_a, pgss_b CASCADE;
+
+--
+-- access to pg_stat_statements_info view
+--
+SELECT pg_stat_statements_reset();
+SELECT dealloc FROM pg_stat_statements_info;
+
+-- FROM [ONLY]
+CREATE TABLE tbl_inh(id integer);
+CREATE TABLE tbl_inh_1() INHERITS (tbl_inh);
+INSERT INTO tbl_inh_1 SELECT 1;
+
+SELECT * FROM tbl_inh;
+SELECT * FROM ONLY tbl_inh;
+
+SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%FROM%tbl_inh%';
+
+-- WITH TIES
+CREATE TABLE limitoption AS SELECT 0 AS val FROM generate_series(1, 10);
+SELECT *
+FROM limitoption
+WHERE val < 2
+ORDER BY val
+FETCH FIRST 2 ROWS WITH TIES;
+
+SELECT *
+FROM limitoption
+WHERE val < 2
+ORDER BY val
+FETCH FIRST 2 ROW ONLY;
+
+SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%FETCH FIRST%';
+
+-- GROUP BY [DISTINCT]
+SELECT a, b, c
+FROM (VALUES (1, 2, 3), (4, NULL, 6), (7, 8, 9)) AS t (a, b, c)
+GROUP BY ROLLUP(a, b), rollup(a, c)
+ORDER BY a, b, c;
+SELECT a, b, c
+FROM (VALUES (1, 2, 3), (4, NULL, 6), (7, 8, 9)) AS t (a, b, c)
+GROUP BY DISTINCT ROLLUP(a, b), rollup(a, c)
+ORDER BY a, b, c;
+
+SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%GROUP BY%ROLLUP%';
+
+-- GROUPING SET agglevelsup
+SELECT (
+ SELECT (
+ SELECT GROUPING(a,b) FROM (VALUES (1)) v2(c)
+ ) FROM (VALUES (1,2)) v1(a,b) GROUP BY (a,b)
+) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
+SELECT (
+ SELECT (
+ SELECT GROUPING(e,f) FROM (VALUES (1)) v2(c)
+ ) FROM (VALUES (1,2)) v1(a,b) GROUP BY (a,b)
+) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
+
+SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%SELECT GROUPING%';
+SELECT pg_stat_statements_reset();
diff --git a/contrib/pg_stat_statements/sql/user_activity.sql b/contrib/pg_stat_statements/sql/user_activity.sql
new file mode 100644
index 0000000000..f8b1ede67b
--- /dev/null
+++ b/contrib/pg_stat_statements/sql/user_activity.sql
@@ -0,0 +1,65 @@
+--
+-- Track user activity and reset them
+--
+
+SET pg_stat_statements.track_utility = TRUE;
+SELECT pg_stat_statements_reset();
+CREATE ROLE regress_stats_user1;
+CREATE ROLE regress_stats_user2;
+
+SET ROLE regress_stats_user1;
+
+SELECT 1 AS "ONE";
+SELECT 1+1 AS "TWO";
+
+RESET ROLE;
+SET ROLE regress_stats_user2;
+
+SELECT 1 AS "ONE";
+SELECT 1+1 AS "TWO";
+
+RESET ROLE;
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+--
+-- Don't reset anything if any of the parameter is NULL
+--
+SELECT pg_stat_statements_reset(NULL);
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+--
+-- remove query ('SELECT $1+$2 AS "TWO"') executed by regress_stats_user2
+-- in the current_database
+--
+SELECT pg_stat_statements_reset(
+ (SELECT r.oid FROM pg_roles AS r WHERE r.rolname = 'regress_stats_user2'),
+ (SELECT d.oid FROM pg_database As d where datname = current_database()),
+ (SELECT s.queryid FROM pg_stat_statements AS s
+ WHERE s.query = 'SELECT $1+$2 AS "TWO"' LIMIT 1));
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+--
+-- remove query ('SELECT $1 AS "ONE"') executed by two users
+--
+SELECT pg_stat_statements_reset(0,0,s.queryid)
+ FROM pg_stat_statements AS s WHERE s.query = 'SELECT $1 AS "ONE"';
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+--
+-- remove query of a user (regress_stats_user1)
+--
+SELECT pg_stat_statements_reset(r.oid)
+ FROM pg_roles AS r WHERE r.rolname = 'regress_stats_user1';
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+--
+-- reset all
+--
+SELECT pg_stat_statements_reset(0,0,0);
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+--
+-- cleanup
+--
+DROP ROLE regress_stats_user1;
+DROP ROLE regress_stats_user2;
diff --git a/contrib/pg_stat_statements/sql/wal.sql b/contrib/pg_stat_statements/sql/wal.sql
new file mode 100644
index 0000000000..34b21c0fa9
--- /dev/null
+++ b/contrib/pg_stat_statements/sql/wal.sql
@@ -0,0 +1,20 @@
+--
+-- Validate WAL generation metrics
+--
+
+SET pg_stat_statements.track_utility = FALSE;
+
+CREATE TABLE pgss_wal_tab (a int, b char(20));
+
+INSERT INTO pgss_wal_tab VALUES(generate_series(1, 10), 'aaa');
+UPDATE pgss_wal_tab SET b = 'bbb' WHERE a > 7;
+DELETE FROM pgss_wal_tab WHERE a > 9;
+DROP TABLE pgss_wal_tab;
+
+-- Check WAL is generated for the above statements
+SELECT query, calls, rows,
+wal_bytes > 0 as wal_bytes_generated,
+wal_records > 0 as wal_records_generated,
+wal_records >= rows as wal_records_ge_rows
+FROM pg_stat_statements ORDER BY query COLLATE "C";
+SELECT pg_stat_statements_reset();