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

Commit46af71f

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 parent4773198 commit46af71f

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
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.262 2010/08/0902:25:05 tgl Exp $
11+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.263 2010/08/0918:50:10 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1099,6 +1099,9 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
10991099
*/
11001100
SPI_restore_connection();
11011101

1102+
/* Must clean up the econtext too */
1103+
exec_eval_cleanup(estate);
1104+
11021105
/* Look for a matching exception handler */
11031106
foreach(e,block->exceptions->exc_list)
11041107
{
@@ -2701,6 +2704,9 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
27012704
*
27022705
* NB: the result of the evaluation is no longer valid after this is done,
27032706
* unless it is a pass-by-value datatype.
2707+
*
2708+
* NB: if you change this code, see also the hacks in exec_assign_value's
2709+
* PLPGSQL_DTYPE_ARRAYELEM case.
27042710
* ----------
27052711
*/
27062712
staticvoid
@@ -3464,6 +3470,10 @@ exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target,
34643470

34653471
/* ----------
34663472
* exec_assign_valuePut a value into a target field
3473+
*
3474+
* Note: in some code paths, this may leak memory in the eval_econtext;
3475+
* we assume that will be cleaned up later by exec_eval_cleanup. We cannot
3476+
* call exec_eval_cleanup here for fear of destroying the input Datum value.
34673477
* ----------
34683478
*/
34693479
staticvoid
@@ -3714,6 +3724,9 @@ exec_assign_value(PLpgSQL_execstate *estate,
37143724

37153725
casePLPGSQL_DTYPE_ARRAYELEM:
37163726
{
3727+
/*
3728+
* Target is an element of an array
3729+
*/
37173730
intnsubscripts;
37183731
inti;
37193732
PLpgSQL_expr*subscripts[MAXDIM];
@@ -3729,10 +3742,19 @@ exec_assign_value(PLpgSQL_execstate *estate,
37293742
coerced_value;
37303743
ArrayType*oldarrayval;
37313744
ArrayType*newarrayval;
3745+
SPITupleTable*save_eval_tuptable;
3746+
3747+
/*
3748+
* We need to do subscript evaluation, which might require
3749+
* evaluating general expressions; and the caller might have
3750+
* done that too in order to prepare the input Datum. We
3751+
* have to save and restore the caller's SPI_execute result,
3752+
* if any.
3753+
*/
3754+
save_eval_tuptable=estate->eval_tuptable;
3755+
estate->eval_tuptable=NULL;
37323756

37333757
/*
3734-
* Target is an element of an array
3735-
*
37363758
* To handle constructs like x[1][2] := something, we have to
37373759
* be prepared to deal with a chain of arrayelem datums. Chase
37383760
* back to find the base array datum, and save the subscript
@@ -3786,8 +3808,23 @@ exec_assign_value(PLpgSQL_execstate *estate,
37863808
ereport(ERROR,
37873809
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
37883810
errmsg("array subscript in assignment must not be null")));
3811+
3812+
/*
3813+
* Clean up in case the subscript expression wasn't simple.
3814+
* We can't do exec_eval_cleanup, but we can do this much
3815+
* (which is safe because the integer subscript value is
3816+
* surely pass-by-value), and we must do it in case the
3817+
* next subscript expression isn't simple either.
3818+
*/
3819+
if (estate->eval_tuptable!=NULL)
3820+
SPI_freetuptable(estate->eval_tuptable);
3821+
estate->eval_tuptable=NULL;
37893822
}
37903823

3824+
/* Now we can restore caller's SPI_execute result if any. */
3825+
Assert(estate->eval_tuptable==NULL);
3826+
estate->eval_tuptable=save_eval_tuptable;
3827+
37913828
/* Coerce source value to match array element type. */
37923829
coerced_value=exec_simple_cast_value(value,
37933830
valtype,

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3945,6 +3945,49 @@ SELECT * FROM leaker_1(true);
39453945

39463946
DROP FUNCTION leaker_1(bool);
39473947
DROP FUNCTION leaker_2(bool);
3948+
-- Test for appropriate cleanup of non-simple expression evaluations
3949+
-- (bug in all versions prior to August 2010)
3950+
CREATE FUNCTION nonsimple_expr_test() RETURNS text[] AS $$
3951+
DECLARE
3952+
arr text[];
3953+
lr text;
3954+
i integer;
3955+
BEGIN
3956+
arr := array[array['foo','bar'], array['baz', 'quux']];
3957+
lr := 'fool';
3958+
i := 1;
3959+
-- use sub-SELECTs to make expressions non-simple
3960+
arr[(SELECT i)][(SELECT i+1)] := (SELECT lr);
3961+
RETURN arr;
3962+
END;
3963+
$$ LANGUAGE plpgsql;
3964+
SELECT nonsimple_expr_test();
3965+
nonsimple_expr_test
3966+
-------------------------
3967+
{{foo,fool},{baz,quux}}
3968+
(1 row)
3969+
3970+
DROP FUNCTION nonsimple_expr_test();
3971+
CREATE FUNCTION nonsimple_expr_test() RETURNS integer AS $$
3972+
declare
3973+
i integer NOT NULL := 0;
3974+
begin
3975+
begin
3976+
i := (SELECT NULL::integer); -- should throw error
3977+
exception
3978+
WHEN OTHERS THEN
3979+
i := (SELECT 1::integer);
3980+
end;
3981+
return i;
3982+
end;
3983+
$$ LANGUAGE plpgsql;
3984+
SELECT nonsimple_expr_test();
3985+
nonsimple_expr_test
3986+
---------------------
3987+
1
3988+
(1 row)
3989+
3990+
DROP FUNCTION nonsimple_expr_test();
39483991
-- Test handling of string literals.
39493992
set standard_conforming_strings = off;
39503993
create or replace function strtest() returns text as $$

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3150,6 +3150,46 @@ SELECT * FROM leaker_1(true);
31503150
DROPFUNCTION leaker_1(bool);
31513151
DROPFUNCTION leaker_2(bool);
31523152

3153+
-- Test for appropriate cleanup of non-simple expression evaluations
3154+
-- (bug in all versions prior to August 2010)
3155+
3156+
CREATEFUNCTIONnonsimple_expr_test() RETURNStext[]AS $$
3157+
DECLARE
3158+
arrtext[];
3159+
lrtext;
3160+
iinteger;
3161+
BEGIN
3162+
arr := array[array['foo','bar'], array['baz','quux']];
3163+
lr :='fool';
3164+
i :=1;
3165+
-- use sub-SELECTs to make expressions non-simple
3166+
arr[(SELECT i)][(SELECT i+1)] := (SELECT lr);
3167+
RETURN arr;
3168+
END;
3169+
$$ LANGUAGE plpgsql;
3170+
3171+
SELECT nonsimple_expr_test();
3172+
3173+
DROPFUNCTION nonsimple_expr_test();
3174+
3175+
CREATEFUNCTIONnonsimple_expr_test() RETURNSintegerAS $$
3176+
declare
3177+
iintegerNOT NULL :=0;
3178+
begin
3179+
begin
3180+
i := (SELECTNULL::integer);-- should throw error
3181+
exception
3182+
WHEN OTHERS THEN
3183+
i := (SELECT1::integer);
3184+
end;
3185+
return i;
3186+
end;
3187+
$$ LANGUAGE plpgsql;
3188+
3189+
SELECT nonsimple_expr_test();
3190+
3191+
DROPFUNCTION nonsimple_expr_test();
3192+
31533193
-- Test handling of string literals.
31543194

31553195
set standard_conforming_strings= off;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp