Skip to content

Commit ef2b138

Browse files
committed
Fix incorrect logic in plpgsql for cleanup after evaluation of non-simple
expressions. We need to deal with this when handling subscripts in an array assignment, and also when catching an exception. In an Assert-enabled build these omissions led to Assert failures, but I think in a normal build the only consequence would be short-term memory leakage; which may explain why this wasn't reported from the field long ago. Back-patch to all supported versions. 7.4 doesn't have exceptions, but otherwise these bugs go all the way back. Heikki Linnakangas and Tom Lane
1 parent 10c0565 commit ef2b138

File tree

3 files changed

+80
-2
lines changed

3 files changed

+80
-2
lines changed

src/pl/plpgsql/src/pl_exec.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.93.2.4 2010/07/05 09:27:57 heikki Exp $
6+
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.93.2.5 2010/08/09 18:51:12 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -1919,6 +1919,9 @@ plpgsql_estate_setup(PLpgSQL_execstate * estate,
19191919
*
19201920
* NB: the result of the evaluation is no longer valid after this is done,
19211921
* unless it is a pass-by-value datatype.
1922+
*
1923+
* NB: if you change this code, see also the hacks in exec_assign_value's
1924+
* PLPGSQL_DTYPE_ARRAYELEM case.
19221925
* ----------
19231926
*/
19241927
static void
@@ -2674,6 +2677,10 @@ exec_assign_expr(PLpgSQL_execstate * estate, PLpgSQL_datum * target,
26742677

26752678
/* ----------
26762679
* exec_assign_value Put a value into a target field
2680+
*
2681+
* Note: in some code paths, this may leak memory in the eval_econtext;
2682+
* we assume that will be cleaned up later by exec_eval_cleanup. We cannot
2683+
* call exec_eval_cleanup here for fear of destroying the input Datum value.
26772684
* ----------
26782685
*/
26792686
static void
@@ -2708,6 +2715,7 @@ exec_assign_value(PLpgSQL_execstate * estate,
27082715
Datum oldarrayval,
27092716
coerced_value;
27102717
ArrayType *newarrayval;
2718+
SPITupleTable *save_eval_tuptable;
27112719
HeapTuple newtup;
27122720

27132721
switch (target->dtype)
@@ -2868,6 +2876,16 @@ exec_assign_value(PLpgSQL_execstate * estate,
28682876
/*
28692877
* Target is an element of an array
28702878
*
2879+
* We need to do subscript evaluation, which might require
2880+
* evaluating general expressions; and the caller might have
2881+
* done that too in order to prepare the input Datum. We
2882+
* have to save and restore the caller's SPI_execute result,
2883+
* if any.
2884+
*/
2885+
save_eval_tuptable = estate->eval_tuptable;
2886+
estate->eval_tuptable = NULL;
2887+
2888+
/*
28712889
* To handle constructs like x[1][2] := something, we have to be
28722890
* prepared to deal with a chain of arrayelem datums. Chase
28732891
* back to find the base array datum, and save the subscript
@@ -2910,8 +2928,23 @@ exec_assign_value(PLpgSQL_execstate * estate,
29102928
subscripts[nsubscripts - 1 - i],
29112929
&subisnull);
29122930
havenullsubscript |= subisnull;
2931+
2932+
/*
2933+
* Clean up in case the subscript expression wasn't simple.
2934+
* We can't do exec_eval_cleanup, but we can do this much
2935+
* (which is safe because the integer subscript value is
2936+
* surely pass-by-value), and we must do it in case the
2937+
* next subscript expression isn't simple either.
2938+
*/
2939+
if (estate->eval_tuptable != NULL)
2940+
SPI_freetuptable(estate->eval_tuptable);
2941+
estate->eval_tuptable = NULL;
29132942
}
29142943

2944+
/* Now we can restore caller's SPI_execute result if any. */
2945+
Assert(estate->eval_tuptable == NULL);
2946+
estate->eval_tuptable = save_eval_tuptable;
2947+
29152948
/*
29162949
* Skip the assignment if we have any nulls, either in the
29172950
* original array value, the subscripts, or the righthand

src/test/regress/expected/plpgsql.out

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,3 +1788,26 @@ SELECT * FROM perform_test;
17881788
(3 rows)
17891789

17901790
drop table perform_test;
1791+
-- Test for appropriate cleanup of non-simple expression evaluations
1792+
-- (bug in all versions prior to August 2010)
1793+
CREATE FUNCTION nonsimple_expr_test() RETURNS text[] AS '
1794+
DECLARE
1795+
arr text[];
1796+
lr text;
1797+
i integer;
1798+
BEGIN
1799+
arr := array[array[''foo'',''bar''], array[''baz'', ''quux'']];
1800+
lr := ''fool'';
1801+
i := 1;
1802+
-- use sub-SELECTs to make expressions non-simple
1803+
arr[(SELECT i)][(SELECT i+1)] := (SELECT lr);
1804+
RETURN arr;
1805+
END;
1806+
' LANGUAGE plpgsql;
1807+
SELECT nonsimple_expr_test();
1808+
nonsimple_expr_test
1809+
-------------------------
1810+
{{foo,fool},{baz,quux}}
1811+
(1 row)
1812+
1813+
DROP FUNCTION nonsimple_expr_test();

src/test/regress/sql/plpgsql.sql

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1603,4 +1603,26 @@ END;' language 'plpgsql';
16031603
SELECT perform_test_func();
16041604
SELECT * FROM perform_test;
16051605

1606-
drop table perform_test;
1606+
drop table perform_test;
1607+
1608+
-- Test for appropriate cleanup of non-simple expression evaluations
1609+
-- (bug in all versions prior to August 2010)
1610+
1611+
CREATE FUNCTION nonsimple_expr_test() RETURNS text[] AS '
1612+
DECLARE
1613+
arr text[];
1614+
lr text;
1615+
i integer;
1616+
BEGIN
1617+
arr := array[array[''foo'',''bar''], array[''baz'', ''quux'']];
1618+
lr := ''fool'';
1619+
i := 1;
1620+
-- use sub-SELECTs to make expressions non-simple
1621+
arr[(SELECT i)][(SELECT i+1)] := (SELECT lr);
1622+
RETURN arr;
1623+
END;
1624+
' LANGUAGE plpgsql;
1625+
1626+
SELECT nonsimple_expr_test();
1627+
1628+
DROP FUNCTION nonsimple_expr_test();

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy