summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorTom Lane2017-12-09 17:03:00 +0000
committerTom Lane2017-12-09 17:03:04 +0000
commit390d58135b22bc25229b524a60f69682182201d8 (patch)
tree013c8060a8fe3245e461a0862c2ad266724b9bb2 /src/test
parentce1468d02bdbbe3aa710463fa9faaf8cf865ad72 (diff)
Fix plpgsql to reinitialize record variables at block re-entry.
If one exits and re-enters a DECLARE ... BEGIN ... END block within a single execution of a plpgsql function, perhaps due to a surrounding loop, the declared variables are supposed to get re-initialized to null (or whatever their initializer is). But this failed to happen for variables of type "record", because while exec_stmt_block() expected such variables to be included in the block's initvarnos list, plpgsql_add_initdatums() only adds DTYPE_VAR variables to that list. This bug appears to have been there since the aboriginal addition of plpgsql to our tree. Fix by teaching plpgsql_add_initdatums() to include DTYPE_REC variables as well. (We don't need to consider other DTYPEs because they don't represent separately-stored values.) I failed to resist the temptation to make some nearby cosmetic adjustments, too. No back-patch, because there have not been field complaints, and it seems possible that somewhere out there someone has code depending on the incorrect behavior. In any case this change would have no impact on correctly-written code. Discussion: https://postgr.es/m/22994.1512800671@sss.pgh.pa.us
Diffstat (limited to 'src/test')
-rw-r--r--src/test/regress/expected/plpgsql.out27
-rw-r--r--src/test/regress/sql/plpgsql.sql21
2 files changed, 48 insertions, 0 deletions
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index d6e5bc33536..29f9e86d560 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -5025,6 +5025,33 @@ select scope_test();
(1 row)
drop function scope_test();
+-- Check that variables are reinitialized on block re-entry.
+do $$
+begin
+ for i in 1..3 loop
+ declare
+ x int;
+ y int := i;
+ r record;
+ begin
+ if i = 1 then
+ x := 42;
+ r := row(i, i+1);
+ end if;
+ raise notice 'x = %', x;
+ raise notice 'y = %', y;
+ raise notice 'r = %', r;
+ end;
+ end loop;
+end$$;
+NOTICE: x = 42
+NOTICE: y = 1
+NOTICE: r = (1,2)
+NOTICE: x = <NULL>
+NOTICE: y = 2
+ERROR: record "r" is not assigned yet
+DETAIL: The tuple structure of a not-yet-assigned record is indeterminate.
+CONTEXT: PL/pgSQL function inline_code_block line 15 at RAISE
-- Check handling of conflicts between plpgsql vars and table columns.
set plpgsql.variable_conflict = error;
create function conflict_test() returns setof int8_tbl as $$
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 1c355132b77..07b6fc89716 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -4014,6 +4014,27 @@ select scope_test();
drop function scope_test();
+-- Check that variables are reinitialized on block re-entry.
+
+do $$
+begin
+ for i in 1..3 loop
+ declare
+ x int;
+ y int := i;
+ r record;
+ begin
+ if i = 1 then
+ x := 42;
+ r := row(i, i+1);
+ end if;
+ raise notice 'x = %', x;
+ raise notice 'y = %', y;
+ raise notice 'r = %', r;
+ end;
+ end loop;
+end$$;
+
-- Check handling of conflicts between plpgsql vars and table columns.
set plpgsql.variable_conflict = error;