aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Conway <neilc@samurai.com>2005-06-22 07:28:47 +0000
committerNeil Conway <neilc@samurai.com>2005-06-22 07:28:47 +0000
commit738df437b277b0e5ed95e5a3bd3da9420839b9ec (patch)
treec28eb53263b53e28a6705e6a3945ba64c2bd2989
parent05db8b501b7807cf730a7c1b8a95d05ca694070b (diff)
downloadpostgresql-738df437b277b0e5ed95e5a3bd3da9420839b9ec.tar.gz
postgresql-738df437b277b0e5ed95e5a3bd3da9420839b9ec.zip
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.
-rw-r--r--src/pl/plpgsql/src/pl_exec.c47
-rw-r--r--src/test/regress/expected/plpgsql.out40
-rw-r--r--src/test/regress/sql/plpgsql.sql28
3 files changed, 92 insertions, 23 deletions
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index d1ea2d843ee..946a5b1c82a 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.147 2005/06/22 01:35:02 neilc Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.148 2005/06/22 07:28:47 neilc Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -1216,11 +1216,9 @@ exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
static int
exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
{
- int rc;
-
for (;;)
{
- rc = exec_stmts(estate, stmt->body);
+ int rc = exec_stmts(estate, stmt->body);
switch (rc)
{
@@ -1271,12 +1269,12 @@ exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
static int
exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
{
- bool value;
- bool isnull;
- int rc;
-
for (;;)
{
+ int rc;
+ bool value;
+ bool isnull;
+
value = exec_eval_boolean(estate, stmt->cond, &isnull);
exec_eval_cleanup(estate);
@@ -1425,21 +1423,22 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
else if (rc == PLPGSQL_RC_CONTINUE)
{
if (estate->exitlabel == NULL)
- /* anonymous continue, so continue the current loop */
- ;
+ /* anonymous continue, so re-run the current loop */
+ rc = PLPGSQL_RC_OK;
else if (stmt->label != NULL &&
strcmp(stmt->label, estate->exitlabel) == 0)
{
- /* labelled continue, matches the current stmt's label */
+ /* label matches named continue, so re-run loop */
estate->exitlabel = NULL;
+ rc = PLPGSQL_RC_OK;
}
else
{
/*
- * otherwise, this is a labelled continue that does
- * not match the current statement's label, if any:
- * return RC_CONTINUE so that the CONTINUE will
- * propagate up the stack.
+ * otherwise, this is a named continue that does not
+ * match the current statement's label, if any: return
+ * RC_CONTINUE so that the CONTINUE will propagate up
+ * the stack.
*/
break;
}
@@ -1555,18 +1554,22 @@ exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
else if (rc == PLPGSQL_RC_CONTINUE)
{
if (estate->exitlabel == NULL)
- /* unlabelled continue, continue the current loop */
+ {
+ /* anonymous continue, so re-run the current loop */
+ rc = PLPGSQL_RC_OK;
continue;
+ }
else if (stmt->label != NULL &&
strcmp(stmt->label, estate->exitlabel) == 0)
{
- /* labelled continue, matches the current stmt's label */
+ /* label matches named continue, so re-run loop */
+ rc = PLPGSQL_RC_OK;
estate->exitlabel = NULL;
continue;
}
/*
- * otherwise, we processed a labelled continue
+ * otherwise, we processed a named continue
* that does not match the current statement's
* label, if any: return RC_CONTINUE so that the
* CONTINUE will propagate up the stack.
@@ -2462,14 +2465,12 @@ static int
exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
{
Datum query;
- bool isnull = false;
+ bool isnull;
Oid restype;
char *querystr;
PLpgSQL_rec *rec = NULL;
PLpgSQL_row *row = NULL;
SPITupleTable *tuptab;
- int rc = PLPGSQL_RC_OK;
- int i;
int n;
void *plan;
Portal portal;
@@ -2536,8 +2537,12 @@ exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
*/
while (n > 0)
{
+ int i;
+
for (i = 0; i < n; i++)
{
+ int rc;
+
/*
* Assign the tuple to the target
*/
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 23ef2d3f2ed..db4aefe6149 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -2547,7 +2547,33 @@ begin
for _r in execute 'select * from conttesttbl' loop
continue when _r.v <= 20;
raise notice '%', _r.v;
- end loop;
+ end loop;
+
+ raise notice '---7---';
+ for _i in 1..3 loop
+ raise notice '%', _i;
+ continue when _i = 3;
+ end loop;
+
+ raise notice '---8---';
+ _i := 1;
+ while _i <= 3 loop
+ raise notice '%', _i;
+ _i := _i + 1;
+ continue when _i = 3;
+ end loop;
+
+ raise notice '---9---';
+ for _r in select * from conttesttbl order by v limit 1 loop
+ raise notice '%', _r.v;
+ continue;
+ end loop;
+
+ raise notice '---10---';
+ for _r in execute 'select * from conttesttbl order by v limit 1' loop
+ raise notice '%', _r.v;
+ continue;
+ end loop;
end; $$ language plpgsql;
select continue_test1();
NOTICE: ---1---
@@ -2591,6 +2617,18 @@ NOTICE: 40
NOTICE: ---6---
NOTICE: 30
NOTICE: 40
+NOTICE: ---7---
+NOTICE: 1
+NOTICE: 2
+NOTICE: 3
+NOTICE: ---8---
+NOTICE: 1
+NOTICE: 2
+NOTICE: 3
+NOTICE: ---9---
+NOTICE: 10
+NOTICE: ---10---
+NOTICE: 10
continue_test1
----------------
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 393fdc52b0c..22cc335e272 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -2169,7 +2169,33 @@ begin
for _r in execute 'select * from conttesttbl' loop
continue when _r.v <= 20;
raise notice '%', _r.v;
- end loop;
+ end loop;
+
+ raise notice '---7---';
+ for _i in 1..3 loop
+ raise notice '%', _i;
+ continue when _i = 3;
+ end loop;
+
+ raise notice '---8---';
+ _i := 1;
+ while _i <= 3 loop
+ raise notice '%', _i;
+ _i := _i + 1;
+ continue when _i = 3;
+ end loop;
+
+ raise notice '---9---';
+ for _r in select * from conttesttbl order by v limit 1 loop
+ raise notice '%', _r.v;
+ continue;
+ end loop;
+
+ raise notice '---10---';
+ for _r in execute 'select * from conttesttbl order by v limit 1' loop
+ raise notice '%', _r.v;
+ continue;
+ end loop;
end; $$ language plpgsql;
select continue_test1();