Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7a3b7bb

Browse files
committed
Fix snapshot leak warning for some procedures
The problem arises with the combination of CALL with output parameters and doing a COMMIT inside the procedure. When a CALL has output parameters, the portal uses the strategy PORTAL_UTIL_SELECT instead of PORTAL_MULTI_QUERY. Using PORTAL_UTIL_SELECT causes the portal's snapshot to be registered with the current resource owner (portal->holdSnapshot); see 9ee1cf0 for the reason. Normally, PortalDrop() unregisters the snapshot. If not, then ResourceOwnerRelease() will print a warning about a snapshot leak on transaction commit. A transaction commit normally drops all portals (PreCommit_Portals()), except the active portal. So in case of the active portal, we need to manually release the snapshot to avoid the warning. Reported-by: Prabhat Sahu <[email protected]> Reviewed-by: Jonathan S. Katz <[email protected]>
1 parent cbdca00 commit 7a3b7bb

File tree

3 files changed

+67
-2
lines changed

3 files changed

+67
-2
lines changed

src/backend/utils/mmgr/portalmem.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -689,13 +689,23 @@ PreCommit_Portals(bool isPrepare)
689689

690690
/*
691691
* Do not touch active portals --- this can only happen in the case of
692-
* a multi-transaction utility command, such as VACUUM.
692+
* a multi-transaction utility command, such as VACUUM, or a commit in
693+
* a procedure.
693694
*
694695
* Note however that any resource owner attached to such a portal is
695-
* still going to go away, so don't leave a dangling pointer.
696+
* still going to go away, so don't leave a dangling pointer. Also
697+
* unregister any snapshots held by the portal, mainly to avoid
698+
* snapshot leak warnings from ResourceOwnerRelease().
696699
*/
697700
if (portal->status == PORTAL_ACTIVE)
698701
{
702+
if (portal->holdSnapshot)
703+
{
704+
if (portal->resowner)
705+
UnregisterSnapshotFromOwner(portal->holdSnapshot,
706+
portal->resowner);
707+
portal->holdSnapshot = NULL;
708+
}
699709
portal->resowner = NULL;
700710
continue;
701711
}

src/pl/plpgsql/src/expected/plpgsql_transaction.out

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,36 @@ SELECT * FROM test2;
463463
42
464464
(1 row)
465465

466+
-- Test transaction in procedure with output parameters. This uses a
467+
-- different portal strategy and different code paths in pquery.c.
468+
CREATE PROCEDURE transaction_test10a(INOUT x int)
469+
LANGUAGE plpgsql
470+
AS $$
471+
BEGIN
472+
x := x + 1;
473+
COMMIT;
474+
END;
475+
$$;
476+
CALL transaction_test10a(10);
477+
x
478+
----
479+
11
480+
(1 row)
481+
482+
CREATE PROCEDURE transaction_test10b(INOUT x int)
483+
LANGUAGE plpgsql
484+
AS $$
485+
BEGIN
486+
x := x - 1;
487+
ROLLBACK;
488+
END;
489+
$$;
490+
CALL transaction_test10b(10);
491+
x
492+
---
493+
9
494+
(1 row)
495+
466496
DROP TABLE test1;
467497
DROP TABLE test2;
468498
DROP TABLE test3;

src/pl/plpgsql/src/sql/plpgsql_transaction.sql

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,31 @@ $$;
387387
SELECT * FROM test2;
388388

389389

390+
-- Test transaction in procedure with output parameters. This uses a
391+
-- different portal strategy and different code paths in pquery.c.
392+
CREATE PROCEDURE transaction_test10a(INOUT x int)
393+
LANGUAGE plpgsql
394+
AS $$
395+
BEGIN
396+
x := x + 1;
397+
COMMIT;
398+
END;
399+
$$;
400+
401+
CALL transaction_test10a(10);
402+
403+
CREATE PROCEDURE transaction_test10b(INOUT x int)
404+
LANGUAGE plpgsql
405+
AS $$
406+
BEGIN
407+
x := x - 1;
408+
ROLLBACK;
409+
END;
410+
$$;
411+
412+
CALL transaction_test10b(10);
413+
414+
390415
DROP TABLE test1;
391416
DROP TABLE test2;
392417
DROP TABLE test3;

0 commit comments

Comments
 (0)