Skip to content

Commit 76bba03

Browse files
committed
Add tests for logging of temporary file removal and statement
Temporary file usage is sometimes attributed to the wrong query in the logs output. One identified reason is that unnamed portal cleanup (and consequently temp file logging) happens during the next BIND message as a, after debug_query_string has already been updated to the new query. Dropping an unnamed portal in the next BIND message is a rather old protocol behavior (fe19e56, also mentioned in the docs). log_temp_files is a bit newer than that, as of be8a431. This commit adds tests to track which query is displayed next to the temporary file(s) removed when a portal is dropped, and in some cases if a query is displayed or not. We have not concluded how to improve the situation yet; these tests will at least help in checking what changes in the logs depending on the proposal discussed and how it affects the scenarios tracked by this new test. Author: Sami Imseih <[email protected]> Author: Frédéric Yhuel <[email protected]> Reviewed-by: Mircea Cadariu <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Discussion: https://postgr.es/m/[email protected]
1 parent 079480d commit 76bba03

File tree

2 files changed

+142
-0
lines changed

2 files changed

+142
-0
lines changed

src/test/modules/test_misc/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ tests += {
1717
't/006_signal_autovacuum.pl',
1818
't/007_catcache_inval.pl',
1919
't/008_replslot_single_user.pl',
20+
't/009_log_temp_files.pl',
2021
],
2122
},
2223
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# Copyright (c) 2025, PostgreSQL Global Development Group
2+
3+
# Check how temporary file removals and statement queries are associated
4+
# in the server logs for various query sequences with the simple and
5+
# extended query protocols.
6+
7+
use strict;
8+
use warnings FATAL => 'all';
9+
use PostgreSQL::Test::Cluster;
10+
use PostgreSQL::Test::Utils;
11+
use Test::More;
12+
13+
# Initialize a new PostgreSQL test cluster
14+
my $node = PostgreSQL::Test::Cluster->new('primary');
15+
$node->init();
16+
$node->append_conf(
17+
'postgresql.conf', qq(
18+
work_mem = 64kB
19+
log_temp_files = 0
20+
debug_parallel_query = off
21+
));
22+
$node->start;
23+
24+
# Setup table and populate with data
25+
$node->safe_psql(
26+
"postgres", qq{
27+
CREATE UNLOGGED TABLE foo(a int);
28+
INSERT INTO foo(a) SELECT * FROM generate_series(1, 5000);
29+
});
30+
31+
note "unnamed portal: temporary file dropped under second SELECT query";
32+
my $log_offset = -s $node->logfile;
33+
$node->safe_psql(
34+
"postgres", qq{
35+
BEGIN;
36+
SELECT a FROM foo ORDER BY a OFFSET \$1 \\bind 4990 \\g
37+
SELECT 'unnamed portal';
38+
END;
39+
});
40+
ok( $node->log_contains(
41+
qr/LOG:\s+temporary file: path.*\n.*\ STATEMENT:\s+SELECT 'unnamed portal'/s,
42+
$log_offset),
43+
"unnamed portal");
44+
45+
note "bind and implicit transaction: temporary file dropped without query";
46+
$log_offset = -s $node->logfile;
47+
$node->safe_psql(
48+
"postgres", qq{
49+
SELECT a FROM foo ORDER BY a OFFSET \$1 \\bind 4991 \\g
50+
});
51+
ok( $node->log_contains(qr/LOG:\s+temporary file:/s, $log_offset),
52+
"bind and implicit transaction, temporary file removed");
53+
ok( !$node->log_contains(qr/STATEMENT:/s, $log_offset),
54+
"bind and implicit transaction, no statement logged");
55+
56+
note "named portal: temporary file dropped under second SELECT query";
57+
$node->safe_psql(
58+
"postgres", qq{
59+
BEGIN;
60+
SELECT a FROM foo ORDER BY a OFFSET \$1 \\parse stmt
61+
\\bind_named stmt 4999 \\g
62+
SELECT 'named portal';
63+
END;
64+
});
65+
ok( $node->log_contains(
66+
qr/LOG:\s+temporary file: path.*\n.*\ STATEMENT:\s+SELECT 'named portal'/s,
67+
$log_offset),
68+
"named portal");
69+
70+
note "pipelined query: temporary file dropped under second SELECT query";
71+
$log_offset = -s $node->logfile;
72+
$node->safe_psql(
73+
"postgres", qq{
74+
\\startpipeline
75+
SELECT a FROM foo ORDER BY a OFFSET \$1 \\bind 4992 \\sendpipeline
76+
SELECT 'pipelined query';
77+
\\endpipeline
78+
});
79+
ok( $node->log_contains(
80+
qr/LOG:\s+temporary file: path.*\n.*\ STATEMENT:\s+SELECT 'pipelined query'/s,
81+
$log_offset),
82+
"pipelined query");
83+
84+
note "parse and bind: temporary file dropped without query";
85+
$log_offset = -s $node->logfile;
86+
$node->safe_psql(
87+
"postgres", qq{
88+
SELECT a, a, a FROM foo ORDER BY a OFFSET \$1 \\parse p1
89+
\\bind_named p1 4993 \\g
90+
});
91+
ok($node->log_contains(qr/LOG:\s+temporary file:/s, $log_offset),
92+
"parse and bind, temporary file removed");
93+
ok(!$node->log_contains(qr/STATEMENT:/s, $log_offset),
94+
"bind and bind, no statement logged");
95+
96+
note "simple query: temporary file dropped under SELECT query";
97+
$log_offset = -s $node->logfile;
98+
$node->safe_psql(
99+
"postgres", qq{
100+
BEGIN;
101+
SELECT a FROM foo ORDER BY a OFFSET 4994;
102+
END;
103+
});
104+
ok( $node->log_contains(
105+
qr/LOG:\s+temporary file: path.*\n.*\ STATEMENT:\s+SELECT a FROM foo ORDER BY a OFFSET 4994;/s,
106+
$log_offset),
107+
"simple query");
108+
109+
note "cursor: temporary file dropped under CLOSE";
110+
$log_offset = -s $node->logfile;
111+
$node->safe_psql(
112+
"postgres", qq{
113+
BEGIN;
114+
DECLARE mycur CURSOR FOR SELECT a FROM foo ORDER BY a OFFSET 4995;
115+
FETCH 10 FROM mycur;
116+
SELECT 1;
117+
CLOSE mycur;
118+
END;
119+
});
120+
ok( $node->log_contains(
121+
qr/LOG:\s+temporary file: path.*\n.*\ STATEMENT:\s+CLOSE mycur;/s,
122+
$log_offset),
123+
"cursor");
124+
125+
note "prepare/execute: temporary file dropped under EXECUTE";
126+
$log_offset = -s $node->logfile;
127+
$node->safe_psql(
128+
"postgres", qq{
129+
BEGIN;
130+
PREPARE p1 AS SELECT a FROM foo ORDER BY a OFFSET 4996;
131+
EXECUTE p1;
132+
DEALLOCATE p1;
133+
END;
134+
});
135+
ok( $node->log_contains(
136+
qr/LOG:\s+temporary file: path.*\n.*\ STATEMENT:\s+EXECUTE p1;/s,
137+
$log_offset),
138+
"prepare/execute");
139+
140+
$node->stop('fast');
141+
done_testing();

0 commit comments

Comments
 (0)