Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd3e41cb

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 arrayassignment, and also when catching an exception. In an Assert-enabled buildthese omissions led to Assert failures, but I think in a normal build theonly consequence would be short-term memory leakage; which may explain whythis wasn't reported from the field long ago.Back-patch to all supported versions. 7.4 doesn't have exceptions, butotherwise these bugs go all the way back.Heikki Linnakangas and Tom Lane
1 parent1eef280 commitd3e41cb

File tree

3 files changed

+123
-3
lines changed

3 files changed

+123
-3
lines changed

‎src/pl/plpgsql/src/pl_exec.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.127.4.9 2010/07/05 09:27:49 heikki Exp $
6+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.127.4.10 2010/08/09 18:51:02 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -970,6 +970,9 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
970970
*/
971971
SPI_restore_connection();
972972

973+
/* Must clean up the econtext too */
974+
exec_eval_cleanup(estate);
975+
973976
/* Look for a matching exception handler */
974977
exceptions=block->exceptions;
975978
for (j=0;j<exceptions->exceptions_used;j++)
@@ -2067,6 +2070,9 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
20672070
*
20682071
* NB: the result of the evaluation is no longer valid after this is done,
20692072
* unless it is a pass-by-value datatype.
2073+
*
2074+
* NB: if you change this code, see also the hacks in exec_assign_value's
2075+
* PLPGSQL_DTYPE_ARRAYELEM case.
20702076
* ----------
20712077
*/
20722078
staticvoid
@@ -2866,6 +2872,10 @@ exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target,
28662872

28672873
/* ----------
28682874
* exec_assign_valuePut a value into a target field
2875+
*
2876+
* Note: in some code paths, this may leak memory in the eval_econtext;
2877+
* we assume that will be cleaned up later by exec_eval_cleanup. We cannot
2878+
* call exec_eval_cleanup here for fear of destroying the input Datum value.
28692879
* ----------
28702880
*/
28712881
staticvoid
@@ -3131,6 +3141,9 @@ exec_assign_value(PLpgSQL_execstate *estate,
31313141

31323142
casePLPGSQL_DTYPE_ARRAYELEM:
31333143
{
3144+
/*
3145+
* Target is an element of an array
3146+
*/
31343147
intnsubscripts;
31353148
inti;
31363149
PLpgSQL_expr*subscripts[MAXDIM];
@@ -3147,10 +3160,19 @@ exec_assign_value(PLpgSQL_execstate *estate,
31473160
coerced_value;
31483161
ArrayType*oldarrayval;
31493162
ArrayType*newarrayval;
3163+
SPITupleTable*save_eval_tuptable;
3164+
3165+
/*
3166+
* We need to do subscript evaluation, which might require
3167+
* evaluating general expressions; and the caller might have
3168+
* done that too in order to prepare the input Datum. We
3169+
* have to save and restore the caller's SPI_execute result,
3170+
* if any.
3171+
*/
3172+
save_eval_tuptable=estate->eval_tuptable;
3173+
estate->eval_tuptable=NULL;
31503174

31513175
/*
3152-
* Target is an element of an array
3153-
*
31543176
* To handle constructs like x[1][2] := something, we have to
31553177
* be prepared to deal with a chain of arrayelem datums.
31563178
* Chase back to find the base array datum, and save the
@@ -3202,8 +3224,23 @@ exec_assign_value(PLpgSQL_execstate *estate,
32023224
subscripts[nsubscripts-1-i],
32033225
&subisnull);
32043226
havenullsubscript |=subisnull;
3227+
3228+
/*
3229+
* Clean up in case the subscript expression wasn't simple.
3230+
* We can't do exec_eval_cleanup, but we can do this much
3231+
* (which is safe because the integer subscript value is
3232+
* surely pass-by-value), and we must do it in case the
3233+
* next subscript expression isn't simple either.
3234+
*/
3235+
if (estate->eval_tuptable!=NULL)
3236+
SPI_freetuptable(estate->eval_tuptable);
3237+
estate->eval_tuptable=NULL;
32053238
}
32063239

3240+
/* Now we can restore caller's SPI_execute result if any. */
3241+
Assert(estate->eval_tuptable==NULL);
3242+
estate->eval_tuptable=save_eval_tuptable;
3243+
32073244
/*
32083245
* Skip the assignment if we have any nulls in the subscripts
32093246
* or the righthand side. This is pretty bogus but it

‎src/test/regress/expected/plpgsql.out

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,3 +2103,46 @@ select sp_add_user('user3');
21032103

21042104
drop function sp_add_user(text);
21052105
drop function sp_id_user(text);
2106+
-- Test for appropriate cleanup of non-simple expression evaluations
2107+
-- (bug in all versions prior to August 2010)
2108+
CREATE FUNCTION nonsimple_expr_test() RETURNS text[] AS $$
2109+
DECLARE
2110+
arr text[];
2111+
lr text;
2112+
i integer;
2113+
BEGIN
2114+
arr := array[array['foo','bar'], array['baz', 'quux']];
2115+
lr := 'fool';
2116+
i := 1;
2117+
-- use sub-SELECTs to make expressions non-simple
2118+
arr[(SELECT i)][(SELECT i+1)] := (SELECT lr);
2119+
RETURN arr;
2120+
END;
2121+
$$ LANGUAGE plpgsql;
2122+
SELECT nonsimple_expr_test();
2123+
nonsimple_expr_test
2124+
-------------------------
2125+
{{foo,fool},{baz,quux}}
2126+
(1 row)
2127+
2128+
DROP FUNCTION nonsimple_expr_test();
2129+
CREATE FUNCTION nonsimple_expr_test() RETURNS integer AS $$
2130+
declare
2131+
i integer NOT NULL := 0;
2132+
begin
2133+
begin
2134+
i := (SELECT NULL::integer); -- should throw error
2135+
exception
2136+
WHEN OTHERS THEN
2137+
i := (SELECT 1::integer);
2138+
end;
2139+
return i;
2140+
end;
2141+
$$ LANGUAGE plpgsql;
2142+
SELECT nonsimple_expr_test();
2143+
nonsimple_expr_test
2144+
---------------------
2145+
1
2146+
(1 row)
2147+
2148+
DROP FUNCTION nonsimple_expr_test();

‎src/test/regress/sql/plpgsql.sql

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1807,3 +1807,43 @@ select sp_add_user('user3');
18071807

18081808
dropfunction sp_add_user(text);
18091809
dropfunction sp_id_user(text);
1810+
1811+
-- Test for appropriate cleanup of non-simple expression evaluations
1812+
-- (bug in all versions prior to August 2010)
1813+
1814+
CREATEFUNCTIONnonsimple_expr_test() RETURNStext[]AS $$
1815+
DECLARE
1816+
arrtext[];
1817+
lrtext;
1818+
iinteger;
1819+
BEGIN
1820+
arr := array[array['foo','bar'], array['baz','quux']];
1821+
lr :='fool';
1822+
i :=1;
1823+
-- use sub-SELECTs to make expressions non-simple
1824+
arr[(SELECT i)][(SELECT i+1)] := (SELECT lr);
1825+
RETURN arr;
1826+
END;
1827+
$$ LANGUAGE plpgsql;
1828+
1829+
SELECT nonsimple_expr_test();
1830+
1831+
DROPFUNCTION nonsimple_expr_test();
1832+
1833+
CREATEFUNCTIONnonsimple_expr_test() RETURNSintegerAS $$
1834+
declare
1835+
iintegerNOT NULL :=0;
1836+
begin
1837+
begin
1838+
i := (SELECTNULL::integer);-- should throw error
1839+
exception
1840+
WHEN OTHERS THEN
1841+
i := (SELECT1::integer);
1842+
end;
1843+
return i;
1844+
end;
1845+
$$ LANGUAGE plpgsql;
1846+
1847+
SELECT nonsimple_expr_test();
1848+
1849+
DROPFUNCTION nonsimple_expr_test();

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp