Skip to content

Commit 738df43

Browse files
author
Neil Conway
committed
Fix bug in CONTINUE statement for PL/pgSQL: when we continue a loop,
we need to be careful to reset rc to PLPGSQL_RC_OK, depending on how the loop's logic is structured. If we continue a loop but it then exits without executing the loop's body again, we want to return PLPGSQL_RC_OK to our caller. Enhance the regression tests to catch this problem. Per report from Michael Fuhr.
1 parent 05db8b5 commit 738df43

File tree

3 files changed

+92
-23
lines changed

3 files changed

+92
-23
lines changed

src/pl/plpgsql/src/pl_exec.c

Lines changed: 26 additions & 21 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.147 2005/06/22 01:35:02 neilc Exp $
6+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.148 2005/06/22 07:28:47 neilc Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -1216,11 +1216,9 @@ exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
12161216
static int
12171217
exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
12181218
{
1219-
int rc;
1220-
12211219
for (;;)
12221220
{
1223-
rc = exec_stmts(estate, stmt->body);
1221+
int rc = exec_stmts(estate, stmt->body);
12241222

12251223
switch (rc)
12261224
{
@@ -1271,12 +1269,12 @@ exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
12711269
static int
12721270
exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
12731271
{
1274-
bool value;
1275-
bool isnull;
1276-
int rc;
1277-
12781272
for (;;)
12791273
{
1274+
int rc;
1275+
bool value;
1276+
bool isnull;
1277+
12801278
value = exec_eval_boolean(estate, stmt->cond, &isnull);
12811279
exec_eval_cleanup(estate);
12821280

@@ -1425,21 +1423,22 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
14251423
else if (rc == PLPGSQL_RC_CONTINUE)
14261424
{
14271425
if (estate->exitlabel == NULL)
1428-
/* anonymous continue, so continue the current loop */
1429-
;
1426+
/* anonymous continue, so re-run the current loop */
1427+
rc = PLPGSQL_RC_OK;
14301428
else if (stmt->label != NULL &&
14311429
strcmp(stmt->label, estate->exitlabel) == 0)
14321430
{
1433-
/* labelled continue, matches the current stmt's label */
1431+
/* label matches named continue, so re-run loop */
14341432
estate->exitlabel = NULL;
1433+
rc = PLPGSQL_RC_OK;
14351434
}
14361435
else
14371436
{
14381437
/*
1439-
* otherwise, this is a labelled continue that does
1440-
* not match the current statement's label, if any:
1441-
* return RC_CONTINUE so that the CONTINUE will
1442-
* propagate up the stack.
1438+
* otherwise, this is a named continue that does not
1439+
* match the current statement's label, if any: return
1440+
* RC_CONTINUE so that the CONTINUE will propagate up
1441+
* the stack.
14431442
*/
14441443
break;
14451444
}
@@ -1555,18 +1554,22 @@ exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
15551554
else if (rc == PLPGSQL_RC_CONTINUE)
15561555
{
15571556
if (estate->exitlabel == NULL)
1558-
/* unlabelled continue, continue the current loop */
1557+
{
1558+
/* anonymous continue, so re-run the current loop */
1559+
rc = PLPGSQL_RC_OK;
15591560
continue;
1561+
}
15601562
else if (stmt->label != NULL &&
15611563
strcmp(stmt->label, estate->exitlabel) == 0)
15621564
{
1563-
/* labelled continue, matches the current stmt's label */
1565+
/* label matches named continue, so re-run loop */
1566+
rc = PLPGSQL_RC_OK;
15641567
estate->exitlabel = NULL;
15651568
continue;
15661569
}
15671570

15681571
/*
1569-
* otherwise, we processed a labelled continue
1572+
* otherwise, we processed a named continue
15701573
* that does not match the current statement's
15711574
* label, if any: return RC_CONTINUE so that the
15721575
* CONTINUE will propagate up the stack.
@@ -2462,14 +2465,12 @@ static int
24622465
exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
24632466
{
24642467
Datum query;
2465-
bool isnull = false;
2468+
bool isnull;
24662469
Oid restype;
24672470
char *querystr;
24682471
PLpgSQL_rec *rec = NULL;
24692472
PLpgSQL_row *row = NULL;
24702473
SPITupleTable *tuptab;
2471-
int rc = PLPGSQL_RC_OK;
2472-
int i;
24732474
int n;
24742475
void *plan;
24752476
Portal portal;
@@ -2536,8 +2537,12 @@ exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
25362537
*/
25372538
while (n > 0)
25382539
{
2540+
int i;
2541+
25392542
for (i = 0; i < n; i++)
25402543
{
2544+
int rc;
2545+
25412546
/*
25422547
* Assign the tuple to the target
25432548
*/

src/test/regress/expected/plpgsql.out

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2547,7 +2547,33 @@ begin
25472547
for _r in execute 'select * from conttesttbl' loop
25482548
continue when _r.v <= 20;
25492549
raise notice '%', _r.v;
2550-
end loop;
2550+
end loop;
2551+
2552+
raise notice '---7---';
2553+
for _i in 1..3 loop
2554+
raise notice '%', _i;
2555+
continue when _i = 3;
2556+
end loop;
2557+
2558+
raise notice '---8---';
2559+
_i := 1;
2560+
while _i <= 3 loop
2561+
raise notice '%', _i;
2562+
_i := _i + 1;
2563+
continue when _i = 3;
2564+
end loop;
2565+
2566+
raise notice '---9---';
2567+
for _r in select * from conttesttbl order by v limit 1 loop
2568+
raise notice '%', _r.v;
2569+
continue;
2570+
end loop;
2571+
2572+
raise notice '---10---';
2573+
for _r in execute 'select * from conttesttbl order by v limit 1' loop
2574+
raise notice '%', _r.v;
2575+
continue;
2576+
end loop;
25512577
end; $$ language plpgsql;
25522578
select continue_test1();
25532579
NOTICE: ---1---
@@ -2591,6 +2617,18 @@ NOTICE: 40
25912617
NOTICE: ---6---
25922618
NOTICE: 30
25932619
NOTICE: 40
2620+
NOTICE: ---7---
2621+
NOTICE: 1
2622+
NOTICE: 2
2623+
NOTICE: 3
2624+
NOTICE: ---8---
2625+
NOTICE: 1
2626+
NOTICE: 2
2627+
NOTICE: 3
2628+
NOTICE: ---9---
2629+
NOTICE: 10
2630+
NOTICE: ---10---
2631+
NOTICE: 10
25942632
continue_test1
25952633
----------------
25962634

src/test/regress/sql/plpgsql.sql

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2169,7 +2169,33 @@ begin
21692169
for _r in execute 'select * from conttesttbl' loop
21702170
continue when _r.v <= 20;
21712171
raise notice '%', _r.v;
2172-
end loop;
2172+
end loop;
2173+
2174+
raise notice '---7---';
2175+
for _i in 1..3 loop
2176+
raise notice '%', _i;
2177+
continue when _i = 3;
2178+
end loop;
2179+
2180+
raise notice '---8---';
2181+
_i := 1;
2182+
while _i <= 3 loop
2183+
raise notice '%', _i;
2184+
_i := _i + 1;
2185+
continue when _i = 3;
2186+
end loop;
2187+
2188+
raise notice '---9---';
2189+
for _r in select * from conttesttbl order by v limit 1 loop
2190+
raise notice '%', _r.v;
2191+
continue;
2192+
end loop;
2193+
2194+
raise notice '---10---';
2195+
for _r in execute 'select * from conttesttbl order by v limit 1' loop
2196+
raise notice '%', _r.v;
2197+
continue;
2198+
end loop;
21732199
end; $$ language plpgsql;
21742200

21752201
select continue_test1();

0 commit comments

Comments
 (0)