mirror of
https://github.com/postgres/postgres.git
synced 2025-10-25 13:17:41 +03:00
Fix the plpgsql memory leak exhibited in bug #4677. That leak was introduced
by my patch of 2007-01-28 to use per-subtransaction ExprContexts/EStates: since we re-prepared any expression tree when the current subtransaction ID changed, we'd accumulate more and more leaked expression state trees in the outermost subtransaction if the same function was executed at multiple levels of subtransaction nesting. To fix, go back to the previous scheme where there was only one EState per transaction for simple plpgsql expressions. We really only need an ExprContext per subtransaction, not a whole EState, so it's possible to keep prepared expression state trees in the one EState throughout the transaction. This should be more efficient as well as not leaking memory for cases involving lots of subtransactions. The added regression test is the case that inspired the 2007-01-28 patch in the first place, just to make sure we didn't go backwards. The current memory leak complaint is unfortunately hard to test for in the regression test framework, though manual testing shows it's fixed. Although this is a pre-existing bug, I'm not back-patching because I'd like to see this method get some field testing first. Consider back-patching if it gets through 8.4beta unscathed.
This commit is contained in:
@@ -2972,3 +2972,36 @@ select * from rttest();
|
||||
|
||||
drop function rttest();
|
||||
|
||||
-- Test for proper cleanup at subtransaction exit. This example
|
||||
-- exposed a bug in PG 8.2.
|
||||
|
||||
CREATE FUNCTION leaker_1(fail BOOL) RETURNS INTEGER AS $$
|
||||
DECLARE
|
||||
v_var INTEGER;
|
||||
BEGIN
|
||||
BEGIN
|
||||
v_var := (leaker_2(fail)).error_code;
|
||||
EXCEPTION
|
||||
WHEN others THEN RETURN 0;
|
||||
END;
|
||||
RETURN 1;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE FUNCTION leaker_2(fail BOOL, OUT error_code INTEGER, OUT new_id INTEGER)
|
||||
RETURNS RECORD AS $$
|
||||
BEGIN
|
||||
IF fail THEN
|
||||
RAISE EXCEPTION 'fail ...';
|
||||
END IF;
|
||||
error_code := 1;
|
||||
new_id := 1;
|
||||
RETURN;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
SELECT * FROM leaker_1(false);
|
||||
SELECT * FROM leaker_1(true);
|
||||
|
||||
DROP FUNCTION leaker_1(bool);
|
||||
DROP FUNCTION leaker_2(bool);
|
||||
|
||||
Reference in New Issue
Block a user