BUG #19107: The hold cursor is unexpectedly released during rollback
Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.
You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:
docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t73381psql -h localhost -U postgresBuilt from patchset v2 (message #2), July 27, 2026 at 06:30 AM.
Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:
git clone --branch t73381_2 https://github.com/hackorum-dev/postgres.gitIn a checkout you already have, add the fork once:
git remote add hackorum https://github.com/hackorum-dev/postgres.gitthen, for this patchset and every later one:
git fetch hackorum t73381_2 && git checkout t73381_2Patchset v2 (message #2) is on t73381_2
The following bug has been logged on the website:
Bug reference: 19107
Logged by: Man Zeng
Email address: zengman@halodbtech.com
PostgreSQL version: 18.0
Operating system: Ubuntu 24.04
Description:
Hi, hackers.
While I was writing test cases for the hold cursor, I unexpectedly
discovered that commit and rollback handle it inconsistently—rollback
unexpectedly releases the hold cursor. Should this be regarded as a bug?
--
Regrads,
Man Zeng
postgres=# -- ok
postgres=# DO $$
DECLARE
val int;
BEGIN
FOR val IN SELECT generate_series(1,10) LOOP
raise notice 'val = %', val;
IF val % 2 = 0 THEN
COMMIT;
ELSE
ROLLBACK;
END IF;
END LOOP;
END; $$;
NOTICE: val = 1
NOTICE: val = 2
NOTICE: val = 3
NOTICE: val = 4
NOTICE: val = 5
NOTICE: val = 6
NOTICE: val = 7
NOTICE: val = 8
NOTICE: val = 9
NOTICE: val = 10
DO
postgres=#
postgres=# -- hold_cursor commit ok
postgres=# do $$
declare
p_CurData refcursor := 'hold_cursor';
val int;
begin
execute 'declare hold_cursor CURSOR WITH HOLD FOR SELECT 42';
loop
fetch p_CurData into val;
exit when val is null;
raise notice 'val = %', val;
commit;
end loop;
close p_CurData;
end; $$;
NOTICE: val = 42
DO
postgres=#
postgres=# -- hold_cursor rollback error
postgres=# do $$
declare
p_CurData refcursor := 'hold_cursor';
val int;
begin
execute 'DECLARE hold_cursor CURSOR WITH HOLD FOR SELECT 42';
loop
fetch p_CurData into val;
exit when val is null;
raise notice 'val = %', val;
rollback;
end loop;
close p_CurData;
end; $$;
NOTICE: val = 42
ERROR: cursor "hold_cursor" does not exist
CONTEXT: PL/pgSQL function inline_code_block line 8 at FETCH
If this is indeed a bug, a simple patch is attached to fix this issue.
PG Bug reporting form <noreply@postgresql.org> writes:
While I was writing test cases for the hold cursor, I unexpectedly
discovered that commit and rollback handle it inconsistently—rollback
unexpectedly releases the hold cursor. Should this be regarded as a bug?
No, that's intentional. The rollback might be cleaning up a failure
in the held cursor.
regards, tom lane