| From: | PG Bug reporting form <noreply(at)postgresql(dot)org> |
|---|---|
| To: | pgsql-bugs(at)lists(dot)postgresql(dot)org |
| Cc: | nickevanoorschot(at)gmail(dot)com |
| Subject: | BUG #19896: transaction_timeout misbehaves after ROLLBACK TO SAVEPOINT and after errors |
| Date: | 2026-11-12 12:41:55 |
| Message-ID: | 19896-555a806fe6352359@postgresql.org |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
The following bug has been logged on the website:
Bug reference: 19896
Logged by: Nicke van Oorschot
Email address: nickevanoorschot(at)gmail(dot)com
PostgreSQL version: 18.6
Operating system: Ubuntu 22.04.5 LTS
Description:
PostgreSQL versions: 18.6; 20devel (development snapshot
postgresql-snapshot.tar.bz2 of
2026-11-12 04:22 UTC, master at debfb3c8a8c93e7bcc3638523b7ffc0846cc2db8).
First observed
on 18.1 ("PostgreSQL 18.1 on x86_64-pc-linux-musl, compiled by gcc (Alpine
15.2.0) 15.2.0, 64-bit").
Documentation of transaction_timeout: "Terminate any session that spans
longer than the
specified amount of time in a transaction." The cases below differ from
that. Each script was
run with "psql -X -f <file>" against a freshly initialised cluster with
default settings.
Output below is from 18.6; 20devel gives the same output apart from the
LOCATION line numbers.
Case 1: a timeout set inside a rolled-back savepoint terminates a later
transaction
--- case1.sql
\set VERBOSITY verbose
-- Transaction 1 sets transaction_timeout inside a savepoint and rolls the
savepoint back.
BEGIN;
SELECT now() AS transaction_1_start;
SAVEPOINT s;
SET LOCAL transaction_timeout = '2s';
ROLLBACK TO SAVEPOINT s;
SHOW transaction_timeout;
COMMIT;
-- Transaction 2 sets a 10 s transaction_timeout and runs for 3 s.
BEGIN;
SELECT now() AS transaction_2_start;
SET LOCAL transaction_timeout = '10s';
SELECT pg_sleep(3);
COMMIT;
SELECT 'transaction 2 committed' AS result;
---
Output:
BEGIN
transaction_1_start
-------------------------------
2026-11-12 11:33:03.520214+00
(1 row)
SAVEPOINT
SET
ROLLBACK
transaction_timeout
---------------------
0
(1 row)
COMMIT
BEGIN
transaction_2_start
-------------------------------
2026-11-12 11:33:03.520757+00
(1 row)
SET
psql:case1.sql:14: FATAL: 25P04: terminating connection due to transaction
timeout
LOCATION: ProcessInterrupts, postgres.c:3498
psql:case1.sql:14: server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
psql:case1.sql:14: error: connection to server was lost
Server log:
2026-11-12 11:33:05.520 UTC [297561] FATAL: terminating connection due to
transaction timeout
2026-11-12 11:33:05.520 UTC [297561] STATEMENT: SELECT pg_sleep(3);
The connection is terminated 2 s after transaction 1 started, while
transaction 2 has run for
less than 2 s with a 10 s transaction_timeout.
Expected: transaction 2 completes and "transaction 2 committed" is returned.
Transaction 1
ended with transaction_timeout = 0, and transaction 2 stays within its 10 s.
Case 2: after an error and ROLLBACK TO SAVEPOINT, the transaction is not
terminated
--- case2.sql
\set VERBOSITY verbose
-- The transaction sets a 2 s transaction_timeout, recovers from an error
with ROLLBACK TO SAVEPOINT, and runs for 3 s.
BEGIN;
SET LOCAL transaction_timeout = '2s';
SAVEPOINT s;
SELECT 1/0;
ROLLBACK TO SAVEPOINT s;
SHOW transaction_timeout;
SELECT pg_sleep(3);
COMMIT;
SELECT 'transaction committed after 3 s' AS result;
---
Output:
BEGIN
SET
SAVEPOINT
psql:case2.sql:6: ERROR: 22012: division by zero
LOCATION: int4div, int.c:870
ROLLBACK
transaction_timeout
---------------------
2s
(1 row)
pg_sleep
----------
(1 row)
COMMIT
result
---------------------------------
transaction committed after 3 s
(1 row)
Expected: the connection is terminated 2 s into the transaction, during
pg_sleep(3), and the
transaction does not commit.
The same script with "SELECT 1;" instead of "SELECT 1/0;" is terminated as
expected:
psql:case2_control.sql:8: FATAL: 25P04: terminating connection due to
transaction timeout
Setting the timeout for the session ("SET transaction_timeout = '2s';"
before BEGIN, no SET
LOCAL) gives the same result as case 2: the transaction commits after 3 s.
Case 3: an aborted transaction is not terminated
--- case3.sql
\set VERBOSITY verbose
-- The transaction sets a 2 s transaction_timeout, fails, and stays open
(aborted) for 3 s.
BEGIN;
SET LOCAL transaction_timeout = '2s';
SELECT 1/0;
\! sleep 3
ROLLBACK;
SELECT 'connection still open after 3 s' AS result;
---
Output:
BEGIN
SET
psql:case3.sql:5: ERROR: 22012: division by zero
LOCATION: int4div, int.c:870
ROLLBACK
result
---------------------------------
connection still open after 3 s
(1 row)
Expected: the connection is terminated 2 s into the transaction, while it is
open in the
aborted state.
Environment of the 18.6 and 20devel runs:
- Built from the source tarballs with
./configure --without-readline --without-zlib --without-icu
--without-openssl; make; make install
(no other deviation from the installation instructions)
- Cluster: initdb -A trust -U postgres, no changes to postgresql.conf
- Server started with: pg_ctl -o "-p <port> -k <socket dir> -c
listen_addresses=''" start
- psql from the same build, run with -X (no .psqlrc)
- OS: Ubuntu 22.04.5 LTS, Linux 7.0.0-43-generic x86_64, glibc 2.35
- Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0
- CPU: AMD Ryzen 9 7940HS (16 threads), 53 GB RAM
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Daniel Gustafsson | 2026-11-12 12:44:57 | Re: BUG #19714: pgcrypto pgp_sym_encrypt accepts nonnumeric s2k-mode as mode 0 |
| Previous Message | shveta malik | 2026-11-12 12:16:16 | Re: BUG #19864: pg_get_publication_tables() gets cache lookup error after concurrent DROP PUBLICATION |