pg_stat_statements: Add more tests for level tracking
authorMichael Paquier <michael@paquier.xyz>
Wed, 21 Jan 2026 09:18:15 +0000 (18:18 +0900)
committerMichael Paquier <michael@paquier.xyz>
Wed, 21 Jan 2026 09:18:15 +0000 (18:18 +0900)
This commit adds tests to verify the computation of the nesting level
for two code paths: the planner hook and the ExecutorFinish() hook.  The
nesting level is essential to save a correct "toplevel" status for the
added PGSS entries.

The author has noticed that removing the manipulations of nesting_level
in these two code paths did not cause the tests to complain, meaning
that we never had coverage for the assumptions taken by the code.

Author: Sami Imseih <samimseih@gmail.com>
Discussion: https://postgr.es/m/CAA5RZ0uK1PSrgf52bWCtDpzaqbWt04o6ZA7zBm6UQyv7vyvf9w@mail.gmail.com

contrib/pg_stat_statements/expected/level_tracking.out
contrib/pg_stat_statements/sql/level_tracking.sql

index 8e8388dd5cb1f924bc6fca6225d24f68301de6ce..35e889fabd274c17e3a4d0b4f486b37326057e4a 100644 (file)
@@ -1535,6 +1535,72 @@ SELECT toplevel, calls, rows, query FROM pg_stat_statements ORDER BY query COLLA
  t        |     1 |    1 | SELECT pg_stat_statements_reset() IS NOT NULL AS t
 (8 rows)
 
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+ t 
+---
+ t
+(1 row)
+
+-- planner - all-level tracking.
+SET pg_stat_statements.track_planning = TRUE;
+SELECT PLUS_THREE(8);
+ plus_three 
+------------
+         11
+(1 row)
+
+SELECT PLUS_THREE(10);
+ plus_three 
+------------
+         13
+(1 row)
+
+SELECT toplevel, calls, rows, plans, query FROM pg_stat_statements
+  ORDER BY query COLLATE "C";
+ toplevel | calls | rows | plans |                               query                                
+----------+-------+------+-------+--------------------------------------------------------------------
+ t        |     2 |    2 |     2 | SELECT PLUS_THREE($1)
+ f        |     2 |    2 |     2 | SELECT i + 3 LIMIT 1
+ t        |     1 |    1 |     0 | SELECT pg_stat_statements_reset() IS NOT NULL AS t
+ t        |     0 |    0 |     1 | SELECT toplevel, calls, rows, plans, query FROM pg_stat_statements+
+          |       |      |       |   ORDER BY query COLLATE "C"
+(4 rows)
+
+RESET pg_stat_statements.track_planning;
+-- AFTER trigger SQL (ExecutorFinish) - all-level tracking.
+SET pg_stat_statements.track = 'all';
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+ t 
+---
+ t
+(1 row)
+
+CREATE TABLE test_trigger (id int, name text);
+CREATE TABLE audit_table (table_name text, action text, row_id int);
+CREATE OR REPLACE FUNCTION audit_trigger_func()
+RETURNS TRIGGER AS $$
+BEGIN
+  INSERT INTO audit_table VALUES ('test_trigger', TG_OP, NEW.id);
+  RETURN NULL;
+END;
+$$ LANGUAGE plpgsql;
+CREATE TRIGGER audit_after_trigger
+  AFTER INSERT ON test_trigger
+  FOR EACH ROW EXECUTE FUNCTION audit_trigger_func();
+INSERT INTO test_trigger VALUES (1, 'test1');
+INSERT INTO test_trigger VALUES (2, 'test2');
+SELECT toplevel, calls, rows, plans, query FROM pg_stat_statements
+  ORDER BY query COLLATE "C";
+ toplevel | calls | rows | plans |                        query                        
+----------+-------+------+-------+-----------------------------------------------------
+ f        |     2 |    2 |     0 | INSERT INTO audit_table VALUES ($15, TG_OP, NEW.id)
+ t        |     2 |    2 |     0 | INSERT INTO test_trigger VALUES ($1, $2)
+ t        |     1 |    1 |     0 | SELECT pg_stat_statements_reset() IS NOT NULL AS t
+(3 rows)
+
+DROP TRIGGER audit_after_trigger ON test_trigger;
+DROP FUNCTION audit_trigger_func();
+DROP TABLE audit_table, test_trigger;
 --
 -- pg_stat_statements.track = none
 --
index 86f007e85524abea06933a328038df6aca778ced..8dd3fc2df089a5d0301cb23ef6bf9e2f5d4214f2 100644 (file)
@@ -431,6 +431,44 @@ SELECT PLUS_THREE(8);
 SELECT PLUS_THREE(10);
 
 SELECT toplevel, calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+
+-- planner - all-level tracking.
+SET pg_stat_statements.track_planning = TRUE;
+
+SELECT PLUS_THREE(8);
+SELECT PLUS_THREE(10);
+
+SELECT toplevel, calls, rows, plans, query FROM pg_stat_statements
+  ORDER BY query COLLATE "C";
+RESET pg_stat_statements.track_planning;
+
+-- AFTER trigger SQL (ExecutorFinish) - all-level tracking.
+SET pg_stat_statements.track = 'all';
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+
+CREATE TABLE test_trigger (id int, name text);
+CREATE TABLE audit_table (table_name text, action text, row_id int);
+CREATE OR REPLACE FUNCTION audit_trigger_func()
+RETURNS TRIGGER AS $$
+BEGIN
+  INSERT INTO audit_table VALUES ('test_trigger', TG_OP, NEW.id);
+  RETURN NULL;
+END;
+$$ LANGUAGE plpgsql;
+CREATE TRIGGER audit_after_trigger
+  AFTER INSERT ON test_trigger
+  FOR EACH ROW EXECUTE FUNCTION audit_trigger_func();
+
+INSERT INTO test_trigger VALUES (1, 'test1');
+INSERT INTO test_trigger VALUES (2, 'test2');
+
+SELECT toplevel, calls, rows, plans, query FROM pg_stat_statements
+  ORDER BY query COLLATE "C";
+
+DROP TRIGGER audit_after_trigger ON test_trigger;
+DROP FUNCTION audit_trigger_func();
+DROP TABLE audit_table, test_trigger;
 
 --
 -- pg_stat_statements.track = none