Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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 <prabhat.sahu@enterprisedb.com> Reviewed-by: Jonathan S. Katz <jkatz@postgresql.org>
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

+12-2
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

+30
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

+25
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)