aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/pg_stat_statements/Makefile2
-rw-r--r--contrib/pg_stat_statements/expected/cleanup.out1
-rw-r--r--contrib/pg_stat_statements/expected/level_tracking.out204
-rw-r--r--contrib/pg_stat_statements/expected/pg_stat_statements.out393
-rw-r--r--contrib/pg_stat_statements/expected/planning.out88
-rw-r--r--contrib/pg_stat_statements/expected/utility.out132
-rw-r--r--contrib/pg_stat_statements/meson.build4
-rw-r--r--contrib/pg_stat_statements/sql/cleanup.sql1
-rw-r--r--contrib/pg_stat_statements/sql/level_tracking.sql99
-rw-r--r--contrib/pg_stat_statements/sql/pg_stat_statements.sql178
-rw-r--r--contrib/pg_stat_statements/sql/planning.sql31
-rw-r--r--contrib/pg_stat_statements/sql/utility.sql60
12 files changed, 623 insertions, 570 deletions
diff --git a/contrib/pg_stat_statements/Makefile b/contrib/pg_stat_statements/Makefile
index edc40c8bbfb..f235f73df56 100644
--- a/contrib/pg_stat_statements/Makefile
+++ b/contrib/pg_stat_statements/Makefile
@@ -17,7 +17,7 @@ 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 oldextversions
+REGRESS = pg_stat_statements utility level_tracking planning 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/cleanup.out b/contrib/pg_stat_statements/expected/cleanup.out
new file mode 100644
index 00000000000..36bec35c406
--- /dev/null
+++ b/contrib/pg_stat_statements/expected/cleanup.out
@@ -0,0 +1 @@
+DROP EXTENSION pg_stat_statements;
diff --git a/contrib/pg_stat_statements/expected/level_tracking.out b/contrib/pg_stat_statements/expected/level_tracking.out
new file mode 100644
index 00000000000..c824ebdac5d
--- /dev/null
+++ b/contrib/pg_stat_statements/expected/level_tracking.out
@@ -0,0 +1,204 @@
+--
+-- Statement level tracking
+--
+SET pg_stat_statements.track_utility = TRUE;
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+-- DO block - top-level tracking.
+CREATE TABLE stats_track_tab (x int);
+SET pg_stat_statements.track = 'top';
+DELETE FROM stats_track_tab;
+DO $$
+BEGIN
+ DELETE FROM stats_track_tab;
+END;
+$$ LANGUAGE plpgsql;
+SELECT toplevel, calls, query FROM pg_stat_statements
+ WHERE query LIKE '%DELETE%' ORDER BY query COLLATE "C", toplevel;
+ toplevel | calls | query
+----------+-------+--------------------------------
+ t | 1 | DELETE FROM stats_track_tab
+ t | 1 | DO $$ +
+ | | BEGIN +
+ | | DELETE FROM stats_track_tab;+
+ | | END; +
+ | | $$ LANGUAGE plpgsql
+(2 rows)
+
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+-- DO block - all-level tracking.
+SET pg_stat_statements.track = 'all';
+DELETE FROM stats_track_tab;
+DO $$
+BEGIN
+ DELETE FROM stats_track_tab;
+END; $$;
+DO LANGUAGE plpgsql $$
+BEGIN
+ -- this is a SELECT
+ PERFORM 'hello world'::TEXT;
+END; $$;
+SELECT toplevel, calls, query FROM pg_stat_statements
+ ORDER BY query COLLATE "C", toplevel;
+ toplevel | calls | query
+----------+-------+--------------------------------------
+ f | 1 | DELETE FROM stats_track_tab
+ t | 1 | DELETE FROM stats_track_tab
+ t | 1 | DO $$ +
+ | | BEGIN +
+ | | DELETE FROM stats_track_tab; +
+ | | END; $$
+ t | 1 | DO LANGUAGE plpgsql $$ +
+ | | BEGIN +
+ | | -- this is a SELECT +
+ | | PERFORM 'hello world'::TEXT; +
+ | | END; $$
+ f | 1 | SELECT $1::TEXT
+ t | 1 | SELECT pg_stat_statements_reset()
+ t | 1 | SET pg_stat_statements.track = 'all'
+(7 rows)
+
+-- PL/pgSQL function - top-level tracking.
+SET pg_stat_statements.track = 'top';
+SET pg_stat_statements.track_utility = FALSE;
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$
+DECLARE
+ r INTEGER;
+BEGIN
+ SELECT (i + 1 + 1.0)::INTEGER INTO r;
+ RETURN r;
+END; $$ LANGUAGE plpgsql;
+SELECT PLUS_TWO(3);
+ plus_two
+----------
+ 5
+(1 row)
+
+SELECT PLUS_TWO(7);
+ plus_two
+----------
+ 9
+(1 row)
+
+-- SQL function --- use LIMIT to keep it from being inlined
+CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS
+$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL;
+SELECT PLUS_ONE(8);
+ plus_one
+----------
+ 9
+(1 row)
+
+SELECT PLUS_ONE(10);
+ plus_one
+----------
+ 11
+(1 row)
+
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+ calls | rows | query
+-------+------+-----------------------------------
+ 2 | 2 | SELECT PLUS_ONE($1)
+ 2 | 2 | SELECT PLUS_TWO($1)
+ 1 | 1 | SELECT pg_stat_statements_reset()
+(3 rows)
+
+-- PL/pgSQL function - all-level tracking.
+SET pg_stat_statements.track = 'all';
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+-- we drop and recreate the functions to avoid any caching funnies
+DROP FUNCTION PLUS_ONE(INTEGER);
+DROP FUNCTION PLUS_TWO(INTEGER);
+-- PL/pgSQL function
+CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$
+DECLARE
+ r INTEGER;
+BEGIN
+ SELECT (i + 1 + 1.0)::INTEGER INTO r;
+ RETURN r;
+END; $$ LANGUAGE plpgsql;
+SELECT PLUS_TWO(-1);
+ plus_two
+----------
+ 1
+(1 row)
+
+SELECT PLUS_TWO(2);
+ plus_two
+----------
+ 4
+(1 row)
+
+-- SQL function --- use LIMIT to keep it from being inlined
+CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS
+$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL;
+SELECT PLUS_ONE(3);
+ plus_one
+----------
+ 4
+(1 row)
+
+SELECT PLUS_ONE(1);
+ plus_one
+----------
+ 2
+(1 row)
+
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+ calls | rows | query
+-------+------+-----------------------------------
+ 2 | 2 | SELECT (i + $2 + $3)::INTEGER
+ 2 | 2 | SELECT (i + $2)::INTEGER LIMIT $3
+ 2 | 2 | SELECT PLUS_ONE($1)
+ 2 | 2 | SELECT PLUS_TWO($1)
+ 1 | 1 | SELECT pg_stat_statements_reset()
+(5 rows)
+
+DROP FUNCTION PLUS_ONE(INTEGER);
+--
+-- pg_stat_statements.track = none
+--
+SET pg_stat_statements.track = 'none';
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+SELECT 1 AS "one";
+ one
+-----
+ 1
+(1 row)
+
+SELECT 1 + 1 AS "two";
+ two
+-----
+ 2
+(1 row)
+
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+ calls | rows | query
+-------+------+-------
+(0 rows)
+
diff --git a/contrib/pg_stat_statements/expected/pg_stat_statements.out b/contrib/pg_stat_statements/expected/pg_stat_statements.out
index 8c0b2235e81..2c5bed841af 100644
--- a/contrib/pg_stat_statements/expected/pg_stat_statements.out
+++ b/contrib/pg_stat_statements/expected/pg_stat_statements.out
@@ -291,9 +291,7 @@ 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
-SET pg_stat_statements.track_utility = TRUE;
DROP TABLE pgss_test;
-SET pg_stat_statements.track_utility = FALSE;
-- Check WAL is generated for the above statements
SELECT query, calls, rows,
wal_bytes > 0 as wal_bytes_generated,
@@ -303,7 +301,6 @@ 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
- DROP TABLE pgss_test | 1 | 0 | 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
@@ -311,158 +308,10 @@ FROM pg_stat_statements ORDER BY query COLLATE "C";
wal_records > $2 as wal_records_generated, +| | | | |
wal_records >= rows as wal_records_ge_rows +| | | | |
FROM pg_stat_statements ORDER BY query COLLATE "C" | | | | |
- SET pg_stat_statements.track_utility = FALSE | 1 | 0 | f | f | t
UPDATE pgss_test SET b = $1 WHERE a > $2 | 1 | 3 | t | t | t
-(7 rows)
-
---
--- pg_stat_statements.track = none
---
-SET pg_stat_statements.track = 'none';
-SELECT pg_stat_statements_reset();
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
-SELECT 1 AS "one";
- one
------
- 1
-(1 row)
-
-SELECT 1 + 1 AS "two";
- two
------
- 2
-(1 row)
-
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
- query | calls | rows
--------+-------+------
-(0 rows)
-
---
--- pg_stat_statements.track = top
---
-SET pg_stat_statements.track = 'top';
-SELECT pg_stat_statements_reset();
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
-DO LANGUAGE plpgsql $$
-BEGIN
- -- this is a SELECT
- PERFORM 'hello world'::TEXT;
-END;
-$$;
--- PL/pgSQL function
-CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$
-DECLARE
- r INTEGER;
-BEGIN
- SELECT (i + 1 + 1.0)::INTEGER INTO r;
- RETURN r;
-END; $$ LANGUAGE plpgsql;
-SELECT PLUS_TWO(3);
- plus_two
-----------
- 5
-(1 row)
-
-SELECT PLUS_TWO(7);
- plus_two
-----------
- 9
-(1 row)
-
--- SQL function --- use LIMIT to keep it from being inlined
-CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS
-$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL;
-SELECT PLUS_ONE(8);
- plus_one
-----------
- 9
-(1 row)
-
-SELECT PLUS_ONE(10);
- plus_one
-----------
- 11
-(1 row)
-
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
- query | calls | rows
-------------------------------------------------------------------------------+-------+------
- SELECT $1::TEXT | 1 | 1
- SELECT PLUS_ONE($1) | 2 | 2
- SELECT PLUS_TWO($1) | 2 | 2
- SELECT pg_stat_statements_reset() | 1 | 1
- SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 0 | 0
(5 rows)
--
--- pg_stat_statements.track = all
---
-SET pg_stat_statements.track = 'all';
-SELECT pg_stat_statements_reset();
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
--- we drop and recreate the functions to avoid any caching funnies
-DROP FUNCTION PLUS_ONE(INTEGER);
-DROP FUNCTION PLUS_TWO(INTEGER);
--- PL/pgSQL function
-CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$
-DECLARE
- r INTEGER;
-BEGIN
- SELECT (i + 1 + 1.0)::INTEGER INTO r;
- RETURN r;
-END; $$ LANGUAGE plpgsql;
-SELECT PLUS_TWO(-1);
- plus_two
-----------
- 1
-(1 row)
-
-SELECT PLUS_TWO(2);
- plus_two
-----------
- 4
-(1 row)
-
--- SQL function --- use LIMIT to keep it from being inlined
-CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS
-$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL;
-SELECT PLUS_ONE(3);
- plus_one
-----------
- 4
-(1 row)
-
-SELECT PLUS_ONE(1);
- plus_one
-----------
- 2
-(1 row)
-
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
- query | calls | rows
-------------------------------------------------------------------------------+-------+------
- SELECT (i + $2 + $3)::INTEGER | 2 | 2
- SELECT (i + $2)::INTEGER LIMIT $3 | 2 | 2
- SELECT PLUS_ONE($1) | 2 | 2
- SELECT PLUS_TWO($1) | 2 | 2
- SELECT pg_stat_statements_reset() | 1 | 1
- SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 0 | 0
-(6 rows)
-
---
-- queries with locking clauses
--
CREATE TABLE pgss_a (id integer PRIMARY KEY);
@@ -551,130 +400,9 @@ SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C";
DROP TABLE pgss_a, pgss_b CASCADE;
--
--- utility commands
---
-SET pg_stat_statements.track_utility = TRUE;
-SELECT pg_stat_statements_reset();
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-CREATE INDEX test_b ON test(b);
-DROP TABLE test \;
-DROP TABLE IF EXISTS test \;
-DROP FUNCTION PLUS_ONE(INTEGER);
-NOTICE: table "test" does not exist, skipping
--- This DROP query uses two different strings, still they count as one entry.
-DROP TABLE IF EXISTS test \;
-Drop Table If Exists test \;
-DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER);
-NOTICE: table "test" does not exist, skipping
-NOTICE: table "test" does not exist, skipping
-NOTICE: function plus_one(pg_catalog.int4) does not exist, skipping
-DROP FUNCTION PLUS_TWO(INTEGER);
--- This SET query uses two different strings, still they count as one entry.
-SET work_mem = '1MB';
-Set work_mem = '1MB';
-SET work_mem = '2MB';
-RESET work_mem;
-SET enable_seqscan = off;
-SET enable_seqscan = on;
-RESET enable_seqscan;
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
- query | calls | rows
-------------------------------------------------------------------------------+-------+------
- CREATE INDEX test_b ON test(b) | 1 | 0
- DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER) | 1 | 0
- DROP FUNCTION PLUS_ONE(INTEGER) | 1 | 0
- DROP FUNCTION PLUS_TWO(INTEGER) | 1 | 0
- DROP TABLE IF EXISTS test | 3 | 0
- DROP TABLE test | 1 | 0
- RESET enable_seqscan | 1 | 0
- RESET work_mem | 1 | 0
- SELECT $1 | 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 enable_seqscan = off | 1 | 0
- SET enable_seqscan = on | 1 | 0
- SET work_mem = '1MB' | 2 | 0
- SET work_mem = '2MB' | 1 | 0
-(15 rows)
-
---
--- Track the total number of rows retrieved or affected by the utility
--- commands of COPY, FETCH, CREATE TABLE AS, CREATE MATERIALIZED VIEW,
--- REFRESH MATERIALIZED VIEW and SELECT INTO
---
-SELECT pg_stat_statements_reset();
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
-CREATE TABLE pgss_ctas AS SELECT a, 'ctas' b FROM generate_series(1, 10) a;
-SELECT generate_series(1, 10) c INTO pgss_select_into;
-COPY pgss_ctas (a, b) FROM STDIN;
-CREATE MATERIALIZED VIEW pgss_matv AS SELECT * FROM pgss_ctas;
-REFRESH MATERIALIZED VIEW pgss_matv;
-BEGIN;
-DECLARE pgss_cursor CURSOR FOR SELECT * FROM pgss_matv;
-FETCH NEXT pgss_cursor;
- a | b
----+------
- 1 | ctas
-(1 row)
-
-FETCH FORWARD 5 pgss_cursor;
- a | b
----+------
- 2 | ctas
- 3 | ctas
- 4 | ctas
- 5 | ctas
- 6 | ctas
-(5 rows)
-
-FETCH FORWARD ALL pgss_cursor;
- a | b
-----+------
- 7 | ctas
- 8 | ctas
- 9 | ctas
- 10 | ctas
- 11 | copy
- 12 | copy
- 13 | copy
-(7 rows)
-
-COMMIT;
-SELECT query, plans, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
- query | plans | calls | rows
--------------------------------------------------------------------------------------+-------+-------+------
- BEGIN | 0 | 1 | 0
- COMMIT | 0 | 1 | 0
- COPY pgss_ctas (a, b) FROM STDIN | 0 | 1 | 3
- CREATE MATERIALIZED VIEW pgss_matv AS SELECT * FROM pgss_ctas | 0 | 1 | 13
- CREATE TABLE pgss_ctas AS SELECT a, 'ctas' b FROM generate_series(1, 10) a | 0 | 1 | 10
- DECLARE pgss_cursor CURSOR FOR SELECT * FROM pgss_matv | 0 | 1 | 0
- FETCH FORWARD 5 pgss_cursor | 0 | 1 | 5
- FETCH FORWARD ALL pgss_cursor | 0 | 1 | 7
- FETCH NEXT pgss_cursor | 0 | 1 | 1
- REFRESH MATERIALIZED VIEW pgss_matv | 0 | 1 | 13
- SELECT generate_series(1, 10) c INTO pgss_select_into | 0 | 1 | 10
- SELECT pg_stat_statements_reset() | 0 | 1 | 1
- SELECT query, plans, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 1 | 0 | 0
-(13 rows)
-
---
-- Track user activity and reset them
--
+SET pg_stat_statements.track_utility = TRUE;
SELECT pg_stat_statements_reset();
pg_stat_statements_reset
--------------------------
@@ -872,84 +600,6 @@ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
--
DROP ROLE regress_stats_user1;
DROP ROLE regress_stats_user2;
-DROP MATERIALIZED VIEW pgss_matv;
-DROP TABLE pgss_ctas;
-DROP TABLE pgss_select_into;
---
--- [re]plan counting
---
-SELECT pg_stat_statements_reset();
- pg_stat_statements_reset
---------------------------
-
-(1 row)
-
-CREATE TABLE test ();
-PREPARE prep1 AS SELECT COUNT(*) FROM test;
-EXECUTE prep1;
- count
--------
- 0
-(1 row)
-
-EXECUTE prep1;
- count
--------
- 0
-(1 row)
-
-EXECUTE prep1;
- count
--------
- 0
-(1 row)
-
-ALTER TABLE test ADD COLUMN x int;
-EXECUTE prep1;
- count
--------
- 0
-(1 row)
-
-SELECT 42;
- ?column?
-----------
- 42
-(1 row)
-
-SELECT 42;
- ?column?
-----------
- 42
-(1 row)
-
-SELECT 42;
- ?column?
-----------
- 42
-(1 row)
-
-SELECT query, plans, calls, rows FROM pg_stat_statements
- WHERE query NOT LIKE 'PREPARE%' ORDER BY query COLLATE "C";
- query | plans | calls | rows
-----------------------------------------------------------+-------+-------+------
- ALTER TABLE test ADD COLUMN x int | 0 | 1 | 0
- CREATE TABLE test () | 0 | 1 | 0
- SELECT $1 | 3 | 3 | 3
- SELECT pg_stat_statements_reset() | 0 | 1 | 1
- SELECT query, plans, calls, rows FROM pg_stat_statements+| 1 | 0 | 0
- WHERE query NOT LIKE $1 ORDER BY query COLLATE "C" | | |
-(5 rows)
-
--- for the prepared statement we expect at least one replan, but cache
--- invalidations could force more
-SELECT query, plans >= 2 AND plans <= calls AS plans_ok, calls, rows FROM pg_stat_statements
- WHERE query LIKE 'PREPARE%' ORDER BY query COLLATE "C";
- query | plans_ok | calls | rows
---------------------------------------------+----------+-------+------
- PREPARE prep1 AS SELECT COUNT(*) FROM test | t | 4 | 4
-(1 row)
-
--
-- access to pg_stat_statements_info view
--
@@ -965,46 +615,6 @@ SELECT dealloc FROM pg_stat_statements_info;
0
(1 row)
---
--- top level handling
---
-SET pg_stat_statements.track = 'top';
-DELETE FROM test;
-DO $$
-BEGIN
- DELETE FROM test;
-END;
-$$ LANGUAGE plpgsql;
-SELECT query, toplevel, plans, calls FROM pg_stat_statements WHERE query LIKE '%DELETE%' ORDER BY query COLLATE "C", toplevel;
- query | toplevel | plans | calls
------------------------+----------+-------+-------
- DELETE FROM test | t | 1 | 1
- DO $$ +| t | 0 | 1
- BEGIN +| | |
- DELETE FROM test;+| | |
- END; +| | |
- $$ LANGUAGE plpgsql | | |
-(2 rows)
-
-SET pg_stat_statements.track = 'all';
-DELETE FROM test;
-DO $$
-BEGIN
- DELETE FROM test;
-END;
-$$ LANGUAGE plpgsql;
-SELECT query, toplevel, plans, calls FROM pg_stat_statements WHERE query LIKE '%DELETE%' ORDER BY query COLLATE "C", toplevel;
- query | toplevel | plans | calls
------------------------+----------+-------+-------
- DELETE FROM test | f | 1 | 1
- DELETE FROM test | t | 2 | 2
- DO $$ +| t | 0 | 2
- BEGIN +| | |
- DELETE FROM test;+| | |
- END; +| | |
- $$ LANGUAGE plpgsql | | |
-(3 rows)
-
-- FROM [ONLY]
CREATE TABLE tbl_inh(id integer);
CREATE TABLE tbl_inh_1() INHERITS (tbl_inh);
@@ -1156,4 +766,3 @@ SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%SELECT GROUPING%';
2
(1 row)
-DROP EXTENSION pg_stat_statements;
diff --git a/contrib/pg_stat_statements/expected/planning.out b/contrib/pg_stat_statements/expected/planning.out
new file mode 100644
index 00000000000..c3561dd7da3
--- /dev/null
+++ b/contrib/pg_stat_statements/expected/planning.out
@@ -0,0 +1,88 @@
+--
+-- Information related to planning
+--
+-- These tests require track_planning to be enabled.
+SET pg_stat_statements.track_planning = TRUE;
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+--
+-- [re]plan counting
+--
+CREATE TABLE stats_plan_test ();
+PREPARE prep1 AS SELECT COUNT(*) FROM stats_plan_test;
+EXECUTE prep1;
+ count
+-------
+ 0
+(1 row)
+
+EXECUTE prep1;
+ count
+-------
+ 0
+(1 row)
+
+EXECUTE prep1;
+ count
+-------
+ 0
+(1 row)
+
+ALTER TABLE stats_plan_test ADD COLUMN x int;
+EXECUTE prep1;
+ count
+-------
+ 0
+(1 row)
+
+SELECT 42;
+ ?column?
+----------
+ 42
+(1 row)
+
+SELECT 42;
+ ?column?
+----------
+ 42
+(1 row)
+
+SELECT 42;
+ ?column?
+----------
+ 42
+(1 row)
+
+SELECT plans, calls, rows, query FROM pg_stat_statements
+ WHERE query NOT LIKE 'PREPARE%' ORDER BY query COLLATE "C";
+ plans | calls | rows | query
+-------+-------+------+----------------------------------------------------------
+ 0 | 1 | 0 | ALTER TABLE stats_plan_test ADD COLUMN x int
+ 0 | 1 | 0 | CREATE TABLE stats_plan_test ()
+ 3 | 3 | 3 | SELECT $1
+ 0 | 1 | 1 | SELECT pg_stat_statements_reset()
+ 1 | 0 | 0 | SELECT plans, calls, rows, query FROM pg_stat_statements+
+ | | | WHERE query NOT LIKE $1 ORDER BY query COLLATE "C"
+(5 rows)
+
+-- for the prepared statement we expect at least one replan, but cache
+-- invalidations could force more
+SELECT plans >= 2 AND plans <= calls AS plans_ok, calls, rows, query FROM pg_stat_statements
+ WHERE query LIKE 'PREPARE%' ORDER BY query COLLATE "C";
+ plans_ok | calls | rows | query
+----------+-------+------+-------------------------------------------------------
+ t | 4 | 4 | PREPARE prep1 AS SELECT COUNT(*) FROM stats_plan_test
+(1 row)
+
+-- Cleanup
+DROP TABLE stats_plan_test;
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
diff --git a/contrib/pg_stat_statements/expected/utility.out b/contrib/pg_stat_statements/expected/utility.out
new file mode 100644
index 00000000000..2395ccd6b45
--- /dev/null
+++ b/contrib/pg_stat_statements/expected/utility.out
@@ -0,0 +1,132 @@
+--
+-- Utility commands
+--
+-- These tests require track_utility to be enabled.
+SET pg_stat_statements.track_utility = TRUE;
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+SELECT 1;
+ ?column?
+----------
+ 1
+(1 row)
+
+CREATE TEMP TABLE stats_util_tab (a int, b char(20));
+CREATE INDEX test_b ON stats_util_tab(b);
+DROP TABLE stats_util_tab \;
+DROP TABLE IF EXISTS stats_util_tab;
+NOTICE: table "stats_util_tab" does not exist, skipping
+-- This DROP query uses two different strings, still they count as one entry.
+DROP TABLE IF EXISTS stats_util_tab \;
+Drop Table If Exists stats_util_tab;
+NOTICE: table "stats_util_tab" does not exist, skipping
+NOTICE: table "stats_util_tab" does not exist, skipping
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+ calls | rows | query
+-------+------+------------------------------------------------------
+ 1 | 0 | CREATE INDEX test_b ON stats_util_tab(b)
+ 1 | 0 | CREATE TEMP TABLE stats_util_tab (a int, b char(20))
+ 3 | 0 | DROP TABLE IF EXISTS stats_util_tab
+ 1 | 0 | DROP TABLE stats_util_tab
+ 1 | 1 | SELECT $1
+ 1 | 1 | SELECT pg_stat_statements_reset()
+(6 rows)
+
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+--
+-- Track the total number of rows retrieved or affected by the utility
+-- commands of COPY, FETCH, CREATE TABLE AS, CREATE MATERIALIZED VIEW,
+-- REFRESH MATERIALIZED VIEW and SELECT INTO
+--
+CREATE TABLE pgss_ctas AS SELECT a, 'ctas' b FROM generate_series(1, 10) a;
+SELECT generate_series(1, 10) c INTO pgss_select_into;
+COPY pgss_ctas (a, b) FROM STDIN;
+CREATE MATERIALIZED VIEW pgss_matv AS SELECT * FROM pgss_ctas;
+REFRESH MATERIALIZED VIEW pgss_matv;
+BEGIN;
+DECLARE pgss_cursor CURSOR FOR SELECT * FROM pgss_matv;
+FETCH NEXT pgss_cursor;
+ a | b
+---+------
+ 1 | ctas
+(1 row)
+
+FETCH FORWARD 5 pgss_cursor;
+ a | b
+---+------
+ 2 | ctas
+ 3 | ctas
+ 4 | ctas
+ 5 | ctas
+ 6 | ctas
+(5 rows)
+
+FETCH FORWARD ALL pgss_cursor;
+ a | b
+----+------
+ 7 | ctas
+ 8 | ctas
+ 9 | ctas
+ 10 | ctas
+ 11 | copy
+ 12 | copy
+ 13 | copy
+(7 rows)
+
+COMMIT;
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+ calls | rows | query
+-------+------+----------------------------------------------------------------------------
+ 1 | 0 | BEGIN
+ 1 | 0 | COMMIT
+ 1 | 3 | COPY pgss_ctas (a, b) FROM STDIN
+ 1 | 13 | CREATE MATERIALIZED VIEW pgss_matv AS SELECT * FROM pgss_ctas
+ 1 | 10 | CREATE TABLE pgss_ctas AS SELECT a, 'ctas' b FROM generate_series(1, 10) a
+ 1 | 0 | DECLARE pgss_cursor CURSOR FOR SELECT * FROM pgss_matv
+ 1 | 5 | FETCH FORWARD 5 pgss_cursor
+ 1 | 7 | FETCH FORWARD ALL pgss_cursor
+ 1 | 1 | FETCH NEXT pgss_cursor
+ 1 | 13 | REFRESH MATERIALIZED VIEW pgss_matv
+ 1 | 10 | SELECT generate_series(1, 10) c INTO pgss_select_into
+ 1 | 1 | SELECT pg_stat_statements_reset()
+(12 rows)
+
+DROP MATERIALIZED VIEW pgss_matv;
+DROP TABLE pgss_ctas;
+DROP TABLE pgss_select_into;
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset
+--------------------------
+
+(1 row)
+
+-- SET statements.
+-- These use two different strings, still they count as one entry.
+SET work_mem = '1MB';
+Set work_mem = '1MB';
+SET work_mem = '2MB';
+RESET work_mem;
+SET enable_seqscan = off;
+SET enable_seqscan = on;
+RESET enable_seqscan;
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+ calls | rows | query
+-------+------+-----------------------------------
+ 1 | 0 | RESET enable_seqscan
+ 1 | 0 | RESET work_mem
+ 1 | 1 | SELECT pg_stat_statements_reset()
+ 1 | 0 | SET enable_seqscan = off
+ 1 | 0 | SET enable_seqscan = on
+ 2 | 0 | SET work_mem = '1MB'
+ 1 | 0 | SET work_mem = '2MB'
+(7 rows)
+
diff --git a/contrib/pg_stat_statements/meson.build b/contrib/pg_stat_statements/meson.build
index 508b53b4a27..93f8b0b3ff8 100644
--- a/contrib/pg_stat_statements/meson.build
+++ b/contrib/pg_stat_statements/meson.build
@@ -41,6 +41,10 @@ tests += {
'regress': {
'sql': [
'pg_stat_statements',
+ 'utility',
+ 'level_tracking',
+ 'planning',
+ 'cleanup',
'oldextversions',
],
'regress_args': ['--temp-config', files('pg_stat_statements.conf')],
diff --git a/contrib/pg_stat_statements/sql/cleanup.sql b/contrib/pg_stat_statements/sql/cleanup.sql
new file mode 100644
index 00000000000..36bec35c406
--- /dev/null
+++ b/contrib/pg_stat_statements/sql/cleanup.sql
@@ -0,0 +1 @@
+DROP EXTENSION pg_stat_statements;
diff --git a/contrib/pg_stat_statements/sql/level_tracking.sql b/contrib/pg_stat_statements/sql/level_tracking.sql
new file mode 100644
index 00000000000..2f95bf98e5c
--- /dev/null
+++ b/contrib/pg_stat_statements/sql/level_tracking.sql
@@ -0,0 +1,99 @@
+--
+-- Statement level tracking
+--
+
+SET pg_stat_statements.track_utility = TRUE;
+SELECT pg_stat_statements_reset();
+
+-- DO block - top-level tracking.
+CREATE TABLE stats_track_tab (x int);
+SET pg_stat_statements.track = 'top';
+DELETE FROM stats_track_tab;
+DO $$
+BEGIN
+ DELETE FROM stats_track_tab;
+END;
+$$ LANGUAGE plpgsql;
+SELECT toplevel, calls, query FROM pg_stat_statements
+ WHERE query LIKE '%DELETE%' ORDER BY query COLLATE "C", toplevel;
+SELECT pg_stat_statements_reset();
+
+-- DO block - all-level tracking.
+SET pg_stat_statements.track = 'all';
+DELETE FROM stats_track_tab;
+DO $$
+BEGIN
+ DELETE FROM stats_track_tab;
+END; $$;
+DO LANGUAGE plpgsql $$
+BEGIN
+ -- this is a SELECT
+ PERFORM 'hello world'::TEXT;
+END; $$;
+SELECT toplevel, calls, query FROM pg_stat_statements
+ ORDER BY query COLLATE "C", toplevel;
+
+-- PL/pgSQL function - top-level tracking.
+SET pg_stat_statements.track = 'top';
+SET pg_stat_statements.track_utility = FALSE;
+SELECT pg_stat_statements_reset();
+CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$
+DECLARE
+ r INTEGER;
+BEGIN
+ SELECT (i + 1 + 1.0)::INTEGER INTO r;
+ RETURN r;
+END; $$ LANGUAGE plpgsql;
+
+SELECT PLUS_TWO(3);
+SELECT PLUS_TWO(7);
+
+-- SQL function --- use LIMIT to keep it from being inlined
+CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS
+$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL;
+
+SELECT PLUS_ONE(8);
+SELECT PLUS_ONE(10);
+
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+-- PL/pgSQL function - all-level tracking.
+SET pg_stat_statements.track = 'all';
+SELECT pg_stat_statements_reset();
+
+-- we drop and recreate the functions to avoid any caching funnies
+DROP FUNCTION PLUS_ONE(INTEGER);
+DROP FUNCTION PLUS_TWO(INTEGER);
+
+-- PL/pgSQL function
+CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$
+DECLARE
+ r INTEGER;
+BEGIN
+ SELECT (i + 1 + 1.0)::INTEGER INTO r;
+ RETURN r;
+END; $$ LANGUAGE plpgsql;
+
+SELECT PLUS_TWO(-1);
+SELECT PLUS_TWO(2);
+
+-- SQL function --- use LIMIT to keep it from being inlined
+CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS
+$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL;
+
+SELECT PLUS_ONE(3);
+SELECT PLUS_ONE(1);
+
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+DROP FUNCTION PLUS_ONE(INTEGER);
+
+--
+-- pg_stat_statements.track = none
+--
+SET pg_stat_statements.track = 'none';
+SELECT pg_stat_statements_reset();
+
+SELECT 1 AS "one";
+SELECT 1 + 1 AS "two";
+
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
diff --git a/contrib/pg_stat_statements/sql/pg_stat_statements.sql b/contrib/pg_stat_statements/sql/pg_stat_statements.sql
index cebde7392b1..3a3d2350667 100644
--- a/contrib/pg_stat_statements/sql/pg_stat_statements.sql
+++ b/contrib/pg_stat_statements/sql/pg_stat_statements.sql
@@ -136,9 +136,7 @@ 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
-SET pg_stat_statements.track_utility = TRUE;
DROP TABLE pgss_test;
-SET pg_stat_statements.track_utility = FALSE;
-- Check WAL is generated for the above statements
SELECT query, calls, rows,
@@ -148,82 +146,6 @@ wal_records >= rows as wal_records_ge_rows
FROM pg_stat_statements ORDER BY query COLLATE "C";
--
--- pg_stat_statements.track = none
---
-SET pg_stat_statements.track = 'none';
-SELECT pg_stat_statements_reset();
-
-SELECT 1 AS "one";
-SELECT 1 + 1 AS "two";
-
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-
---
--- pg_stat_statements.track = top
---
-SET pg_stat_statements.track = 'top';
-SELECT pg_stat_statements_reset();
-
-DO LANGUAGE plpgsql $$
-BEGIN
- -- this is a SELECT
- PERFORM 'hello world'::TEXT;
-END;
-$$;
-
--- PL/pgSQL function
-CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$
-DECLARE
- r INTEGER;
-BEGIN
- SELECT (i + 1 + 1.0)::INTEGER INTO r;
- RETURN r;
-END; $$ LANGUAGE plpgsql;
-
-SELECT PLUS_TWO(3);
-SELECT PLUS_TWO(7);
-
--- SQL function --- use LIMIT to keep it from being inlined
-CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS
-$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL;
-
-SELECT PLUS_ONE(8);
-SELECT PLUS_ONE(10);
-
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-
---
--- pg_stat_statements.track = all
---
-SET pg_stat_statements.track = 'all';
-SELECT pg_stat_statements_reset();
-
--- we drop and recreate the functions to avoid any caching funnies
-DROP FUNCTION PLUS_ONE(INTEGER);
-DROP FUNCTION PLUS_TWO(INTEGER);
-
--- PL/pgSQL function
-CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$
-DECLARE
- r INTEGER;
-BEGIN
- SELECT (i + 1 + 1.0)::INTEGER INTO r;
- RETURN r;
-END; $$ LANGUAGE plpgsql;
-
-SELECT PLUS_TWO(-1);
-SELECT PLUS_TWO(2);
-
--- SQL function --- use LIMIT to keep it from being inlined
-CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS
-$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL;
-
-SELECT PLUS_ONE(3);
-SELECT PLUS_ONE(1);
-
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-
---
-- queries with locking clauses
--
CREATE TABLE pgss_a (id integer PRIMARY KEY);
@@ -255,60 +177,9 @@ SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C";
DROP TABLE pgss_a, pgss_b CASCADE;
--
--- utility commands
---
-SET pg_stat_statements.track_utility = TRUE;
-SELECT pg_stat_statements_reset();
-
-SELECT 1;
-CREATE INDEX test_b ON test(b);
-DROP TABLE test \;
-DROP TABLE IF EXISTS test \;
-DROP FUNCTION PLUS_ONE(INTEGER);
--- This DROP query uses two different strings, still they count as one entry.
-DROP TABLE IF EXISTS test \;
-Drop Table If Exists test \;
-DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER);
-DROP FUNCTION PLUS_TWO(INTEGER);
--- This SET query uses two different strings, still they count as one entry.
-SET work_mem = '1MB';
-Set work_mem = '1MB';
-SET work_mem = '2MB';
-RESET work_mem;
-SET enable_seqscan = off;
-SET enable_seqscan = on;
-RESET enable_seqscan;
-
-SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-
---
--- Track the total number of rows retrieved or affected by the utility
--- commands of COPY, FETCH, CREATE TABLE AS, CREATE MATERIALIZED VIEW,
--- REFRESH MATERIALIZED VIEW and SELECT INTO
---
-SELECT pg_stat_statements_reset();
-
-CREATE TABLE pgss_ctas AS SELECT a, 'ctas' b FROM generate_series(1, 10) a;
-SELECT generate_series(1, 10) c INTO pgss_select_into;
-COPY pgss_ctas (a, b) FROM STDIN;
-11 copy
-12 copy
-13 copy
-\.
-CREATE MATERIALIZED VIEW pgss_matv AS SELECT * FROM pgss_ctas;
-REFRESH MATERIALIZED VIEW pgss_matv;
-BEGIN;
-DECLARE pgss_cursor CURSOR FOR SELECT * FROM pgss_matv;
-FETCH NEXT pgss_cursor;
-FETCH FORWARD 5 pgss_cursor;
-FETCH FORWARD ALL pgss_cursor;
-COMMIT;
-
-SELECT query, plans, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-
---
-- 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;
@@ -369,30 +240,6 @@ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
--
DROP ROLE regress_stats_user1;
DROP ROLE regress_stats_user2;
-DROP MATERIALIZED VIEW pgss_matv;
-DROP TABLE pgss_ctas;
-DROP TABLE pgss_select_into;
-
---
--- [re]plan counting
---
-SELECT pg_stat_statements_reset();
-CREATE TABLE test ();
-PREPARE prep1 AS SELECT COUNT(*) FROM test;
-EXECUTE prep1;
-EXECUTE prep1;
-EXECUTE prep1;
-ALTER TABLE test ADD COLUMN x int;
-EXECUTE prep1;
-SELECT 42;
-SELECT 42;
-SELECT 42;
-SELECT query, plans, calls, rows FROM pg_stat_statements
- WHERE query NOT LIKE 'PREPARE%' ORDER BY query COLLATE "C";
--- for the prepared statement we expect at least one replan, but cache
--- invalidations could force more
-SELECT query, plans >= 2 AND plans <= calls AS plans_ok, calls, rows FROM pg_stat_statements
- WHERE query LIKE 'PREPARE%' ORDER BY query COLLATE "C";
--
-- access to pg_stat_statements_info view
@@ -400,27 +247,6 @@ SELECT query, plans >= 2 AND plans <= calls AS plans_ok, calls, rows FROM pg_sta
SELECT pg_stat_statements_reset();
SELECT dealloc FROM pg_stat_statements_info;
---
--- top level handling
---
-SET pg_stat_statements.track = 'top';
-DELETE FROM test;
-DO $$
-BEGIN
- DELETE FROM test;
-END;
-$$ LANGUAGE plpgsql;
-SELECT query, toplevel, plans, calls FROM pg_stat_statements WHERE query LIKE '%DELETE%' ORDER BY query COLLATE "C", toplevel;
-
-SET pg_stat_statements.track = 'all';
-DELETE FROM test;
-DO $$
-BEGIN
- DELETE FROM test;
-END;
-$$ LANGUAGE plpgsql;
-SELECT query, toplevel, plans, calls FROM pg_stat_statements WHERE query LIKE '%DELETE%' ORDER BY query COLLATE "C", toplevel;
-
-- FROM [ONLY]
CREATE TABLE tbl_inh(id integer);
CREATE TABLE tbl_inh_1() INHERITS (tbl_inh);
@@ -472,5 +298,3 @@ SELECT (
) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%SELECT GROUPING%';
-
-DROP EXTENSION pg_stat_statements;
diff --git a/contrib/pg_stat_statements/sql/planning.sql b/contrib/pg_stat_statements/sql/planning.sql
new file mode 100644
index 00000000000..a59b9363c4b
--- /dev/null
+++ b/contrib/pg_stat_statements/sql/planning.sql
@@ -0,0 +1,31 @@
+--
+-- Information related to planning
+--
+
+-- These tests require track_planning to be enabled.
+SET pg_stat_statements.track_planning = TRUE;
+SELECT pg_stat_statements_reset();
+
+--
+-- [re]plan counting
+--
+CREATE TABLE stats_plan_test ();
+PREPARE prep1 AS SELECT COUNT(*) FROM stats_plan_test;
+EXECUTE prep1;
+EXECUTE prep1;
+EXECUTE prep1;
+ALTER TABLE stats_plan_test ADD COLUMN x int;
+EXECUTE prep1;
+SELECT 42;
+SELECT 42;
+SELECT 42;
+SELECT plans, calls, rows, query FROM pg_stat_statements
+ WHERE query NOT LIKE 'PREPARE%' ORDER BY query COLLATE "C";
+-- for the prepared statement we expect at least one replan, but cache
+-- invalidations could force more
+SELECT plans >= 2 AND plans <= calls AS plans_ok, calls, rows, query FROM pg_stat_statements
+ WHERE query LIKE 'PREPARE%' ORDER BY query COLLATE "C";
+
+-- Cleanup
+DROP TABLE stats_plan_test;
+SELECT pg_stat_statements_reset();
diff --git a/contrib/pg_stat_statements/sql/utility.sql b/contrib/pg_stat_statements/sql/utility.sql
new file mode 100644
index 00000000000..8710b55cf9e
--- /dev/null
+++ b/contrib/pg_stat_statements/sql/utility.sql
@@ -0,0 +1,60 @@
+--
+-- Utility commands
+--
+
+-- These tests require track_utility to be enabled.
+SET pg_stat_statements.track_utility = TRUE;
+SELECT pg_stat_statements_reset();
+
+SELECT 1;
+CREATE TEMP TABLE stats_util_tab (a int, b char(20));
+CREATE INDEX test_b ON stats_util_tab(b);
+DROP TABLE stats_util_tab \;
+DROP TABLE IF EXISTS stats_util_tab;
+-- This DROP query uses two different strings, still they count as one entry.
+DROP TABLE IF EXISTS stats_util_tab \;
+Drop Table If Exists stats_util_tab;
+
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+SELECT pg_stat_statements_reset();
+
+--
+-- Track the total number of rows retrieved or affected by the utility
+-- commands of COPY, FETCH, CREATE TABLE AS, CREATE MATERIALIZED VIEW,
+-- REFRESH MATERIALIZED VIEW and SELECT INTO
+--
+CREATE TABLE pgss_ctas AS SELECT a, 'ctas' b FROM generate_series(1, 10) a;
+SELECT generate_series(1, 10) c INTO pgss_select_into;
+COPY pgss_ctas (a, b) FROM STDIN;
+11 copy
+12 copy
+13 copy
+\.
+CREATE MATERIALIZED VIEW pgss_matv AS SELECT * FROM pgss_ctas;
+REFRESH MATERIALIZED VIEW pgss_matv;
+BEGIN;
+DECLARE pgss_cursor CURSOR FOR SELECT * FROM pgss_matv;
+FETCH NEXT pgss_cursor;
+FETCH FORWARD 5 pgss_cursor;
+FETCH FORWARD ALL pgss_cursor;
+COMMIT;
+
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+DROP MATERIALIZED VIEW pgss_matv;
+DROP TABLE pgss_ctas;
+DROP TABLE pgss_select_into;
+
+SELECT pg_stat_statements_reset();
+
+-- SET statements.
+-- These use two different strings, still they count as one entry.
+SET work_mem = '1MB';
+Set work_mem = '1MB';
+SET work_mem = '2MB';
+RESET work_mem;
+SET enable_seqscan = off;
+SET enable_seqscan = on;
+RESET enable_seqscan;
+
+SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";