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

Commit390d581

Browse files
committed
Fix plpgsql to reinitialize record variables at block re-entry.
If one exits and re-enters a DECLARE ... BEGIN ... END block within asingle execution of a plpgsql function, perhaps due to a surrounding loop,the declared variables are supposed to get re-initialized to null (orwhatever their initializer is). But this failed to happen for variablesof type "record", because while exec_stmt_block() expected such variablesto be included in the block's initvarnos list, plpgsql_add_initdatums()only adds DTYPE_VAR variables to that list. This bug appears to havebeen there since the aboriginal addition of plpgsql to our tree.Fix by teaching plpgsql_add_initdatums() to include DTYPE_REC variablesas well. (We don't need to consider other DTYPEs because they don'trepresent separately-stored values.) I failed to resist the temptationto make some nearby cosmetic adjustments, too.No back-patch, because there have not been field complaints, and itseems possible that somewhere out there someone has code dependingon the incorrect behavior. In any case this change would have noimpact on correctly-written code.Discussion:https://postgr.es/m/22994.1512800671@sss.pgh.pa.us
1 parentce1468d commit390d581

File tree

5 files changed

+68
-16
lines changed

5 files changed

+68
-16
lines changed

‎src/pl/plpgsql/src/pl_comp.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2384,14 +2384,14 @@ plpgsql_finish_datums(PLpgSQL_function *function)
23842384

23852385
/* ----------
23862386
* plpgsql_add_initdatumsMake an array of the datum numbers of
2387-
*all thesimple VAR datums created since the last call
2387+
*all theinitializable datums created since the last call
23882388
*to this function.
23892389
*
23902390
* If varnos is NULL, we just forget any datum entries created since the
23912391
* last call.
23922392
*
2393-
* This is used around a DECLARE section to create a list of theVARs
2394-
* that have to be initialized at block entry. Note thatVARs can also
2393+
* This is used around a DECLARE section to create a list of thedatums
2394+
* that have to be initialized at block entry. Note thatdatums can also
23952395
* be created elsewhere than DECLARE, eg by a FOR-loop, but it is then
23962396
* the responsibility of special-purpose code to initialize them.
23972397
* ----------
@@ -2402,11 +2402,16 @@ plpgsql_add_initdatums(int **varnos)
24022402
inti;
24032403
intn=0;
24042404

2405+
/*
2406+
* The set of dtypes recognized here must match what exec_stmt_block()
2407+
* cares about (re)initializing at block entry.
2408+
*/
24052409
for (i=datums_last;i<plpgsql_nDatums;i++)
24062410
{
24072411
switch (plpgsql_Datums[i]->dtype)
24082412
{
24092413
casePLPGSQL_DTYPE_VAR:
2414+
casePLPGSQL_DTYPE_REC:
24102415
n++;
24112416
break;
24122417

@@ -2427,6 +2432,7 @@ plpgsql_add_initdatums(int **varnos)
24272432
switch (plpgsql_Datums[i]->dtype)
24282433
{
24292434
casePLPGSQL_DTYPE_VAR:
2435+
casePLPGSQL_DTYPE_REC:
24302436
(*varnos)[n++]=plpgsql_Datums[i]->dno;
24312437

24322438
default:

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

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,7 +1184,6 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
11841184
{
11851185
volatileintrc=-1;
11861186
inti;
1187-
intn;
11881187

11891188
/*
11901189
* First initialize all variables declared in this block
@@ -1193,13 +1192,17 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
11931192

11941193
for (i=0;i<block->n_initvars;i++)
11951194
{
1196-
n=block->initvarnos[i];
1195+
intn=block->initvarnos[i];
1196+
PLpgSQL_datum*datum=estate->datums[n];
11971197

1198-
switch (estate->datums[n]->dtype)
1198+
/*
1199+
* The set of dtypes handled here must match plpgsql_add_initdatums().
1200+
*/
1201+
switch (datum->dtype)
11991202
{
12001203
casePLPGSQL_DTYPE_VAR:
12011204
{
1202-
PLpgSQL_var*var= (PLpgSQL_var*)(estate->datums[n]);
1205+
PLpgSQL_var*var= (PLpgSQL_var*)datum;
12031206

12041207
/*
12051208
* Free any old value, in case re-entering block, and
@@ -1241,7 +1244,7 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
12411244

12421245
casePLPGSQL_DTYPE_REC:
12431246
{
1244-
PLpgSQL_rec*rec= (PLpgSQL_rec*)(estate->datums[n]);
1247+
PLpgSQL_rec*rec= (PLpgSQL_rec*)datum;
12451248

12461249
if (rec->freetup)
12471250
{
@@ -1258,13 +1261,8 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
12581261
}
12591262
break;
12601263

1261-
casePLPGSQL_DTYPE_RECFIELD:
1262-
casePLPGSQL_DTYPE_ARRAYELEM:
1263-
break;
1264-
12651264
default:
1266-
elog(ERROR,"unrecognized dtype: %d",
1267-
estate->datums[n]->dtype);
1265+
elog(ERROR,"unrecognized dtype: %d",datum->dtype);
12681266
}
12691267
}
12701268

‎src/pl/plpgsql/src/plpgsql.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,8 +407,8 @@ typedef struct PLpgSQL_stmt_block
407407
intlineno;
408408
char*label;
409409
List*body;/* List of statements */
410-
intn_initvars;
411-
int*initvarnos;
410+
intn_initvars;/* Length of initvarnos[] */
411+
int*initvarnos;/* dnos of variables declared in this block */
412412
PLpgSQL_exception_block*exceptions;
413413
}PLpgSQL_stmt_block;
414414

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5025,6 +5025,33 @@ select scope_test();
50255025
(1 row)
50265026

50275027
drop function scope_test();
5028+
-- Check that variables are reinitialized on block re-entry.
5029+
do $$
5030+
begin
5031+
for i in 1..3 loop
5032+
declare
5033+
x int;
5034+
y int := i;
5035+
r record;
5036+
begin
5037+
if i = 1 then
5038+
x := 42;
5039+
r := row(i, i+1);
5040+
end if;
5041+
raise notice 'x = %', x;
5042+
raise notice 'y = %', y;
5043+
raise notice 'r = %', r;
5044+
end;
5045+
end loop;
5046+
end$$;
5047+
NOTICE: x = 42
5048+
NOTICE: y = 1
5049+
NOTICE: r = (1,2)
5050+
NOTICE: x = <NULL>
5051+
NOTICE: y = 2
5052+
ERROR: record "r" is not assigned yet
5053+
DETAIL: The tuple structure of a not-yet-assigned record is indeterminate.
5054+
CONTEXT: PL/pgSQL function inline_code_block line 15 at RAISE
50285055
-- Check handling of conflicts between plpgsql vars and table columns.
50295056
set plpgsql.variable_conflict = error;
50305057
create function conflict_test() returns setof int8_tbl as $$

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4014,6 +4014,27 @@ select scope_test();
40144014
40154015
drop function scope_test();
40164016
4017+
-- Check that variables are reinitialized on block re-entry.
4018+
4019+
do $$
4020+
begin
4021+
for i in 1..3 loop
4022+
declare
4023+
x int;
4024+
y int := i;
4025+
r record;
4026+
begin
4027+
if i = 1 then
4028+
x := 42;
4029+
r := row(i, i+1);
4030+
end if;
4031+
raise notice'x= %', x;
4032+
raise notice'y= %', y;
4033+
raise notice'r= %', r;
4034+
end;
4035+
end loop;
4036+
end$$;
4037+
40174038
-- Check handling of conflicts between plpgsql vars and table columns.
40184039
40194040
set plpgsql.variable_conflict = error;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp