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.
This commit is contained in:
parent
05db8b501b
commit
738df437b2
@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -1216,11 +1216,9 @@ exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
|
|||||||
static int
|
static int
|
||||||
exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
|
exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
|
||||||
{
|
{
|
||||||
int rc;
|
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
rc = exec_stmts(estate, stmt->body);
|
int rc = exec_stmts(estate, stmt->body);
|
||||||
|
|
||||||
switch (rc)
|
switch (rc)
|
||||||
{
|
{
|
||||||
@ -1271,12 +1269,12 @@ exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
|
|||||||
static int
|
static int
|
||||||
exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
|
exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
|
||||||
{
|
{
|
||||||
bool value;
|
|
||||||
bool isnull;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
|
bool value;
|
||||||
|
bool isnull;
|
||||||
|
|
||||||
value = exec_eval_boolean(estate, stmt->cond, &isnull);
|
value = exec_eval_boolean(estate, stmt->cond, &isnull);
|
||||||
exec_eval_cleanup(estate);
|
exec_eval_cleanup(estate);
|
||||||
|
|
||||||
@ -1425,21 +1423,22 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
|
|||||||
else if (rc == PLPGSQL_RC_CONTINUE)
|
else if (rc == PLPGSQL_RC_CONTINUE)
|
||||||
{
|
{
|
||||||
if (estate->exitlabel == NULL)
|
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 &&
|
else if (stmt->label != NULL &&
|
||||||
strcmp(stmt->label, estate->exitlabel) == 0)
|
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;
|
estate->exitlabel = NULL;
|
||||||
|
rc = PLPGSQL_RC_OK;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* otherwise, this is a labelled continue that does
|
* otherwise, this is a named continue that does not
|
||||||
* not match the current statement's label, if any:
|
* match the current statement's label, if any: return
|
||||||
* return RC_CONTINUE so that the CONTINUE will
|
* RC_CONTINUE so that the CONTINUE will propagate up
|
||||||
* propagate up the stack.
|
* the stack.
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1555,18 +1554,22 @@ exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
|
|||||||
else if (rc == PLPGSQL_RC_CONTINUE)
|
else if (rc == PLPGSQL_RC_CONTINUE)
|
||||||
{
|
{
|
||||||
if (estate->exitlabel == NULL)
|
if (estate->exitlabel == NULL)
|
||||||
/* unlabelled continue, continue the current loop */
|
{
|
||||||
|
/* anonymous continue, so re-run the current loop */
|
||||||
|
rc = PLPGSQL_RC_OK;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
else if (stmt->label != NULL &&
|
else if (stmt->label != NULL &&
|
||||||
strcmp(stmt->label, estate->exitlabel) == 0)
|
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;
|
estate->exitlabel = NULL;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* otherwise, we processed a labelled continue
|
* otherwise, we processed a named continue
|
||||||
* that does not match the current statement's
|
* that does not match the current statement's
|
||||||
* label, if any: return RC_CONTINUE so that the
|
* label, if any: return RC_CONTINUE so that the
|
||||||
* CONTINUE will propagate up the stack.
|
* CONTINUE will propagate up the stack.
|
||||||
@ -2462,14 +2465,12 @@ static int
|
|||||||
exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
|
exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
|
||||||
{
|
{
|
||||||
Datum query;
|
Datum query;
|
||||||
bool isnull = false;
|
bool isnull;
|
||||||
Oid restype;
|
Oid restype;
|
||||||
char *querystr;
|
char *querystr;
|
||||||
PLpgSQL_rec *rec = NULL;
|
PLpgSQL_rec *rec = NULL;
|
||||||
PLpgSQL_row *row = NULL;
|
PLpgSQL_row *row = NULL;
|
||||||
SPITupleTable *tuptab;
|
SPITupleTable *tuptab;
|
||||||
int rc = PLPGSQL_RC_OK;
|
|
||||||
int i;
|
|
||||||
int n;
|
int n;
|
||||||
void *plan;
|
void *plan;
|
||||||
Portal portal;
|
Portal portal;
|
||||||
@ -2536,8 +2537,12 @@ exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
|
|||||||
*/
|
*/
|
||||||
while (n > 0)
|
while (n > 0)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Assign the tuple to the target
|
* Assign the tuple to the target
|
||||||
*/
|
*/
|
||||||
|
@ -2548,6 +2548,32 @@ begin
|
|||||||
continue when _r.v <= 20;
|
continue when _r.v <= 20;
|
||||||
raise notice '%', _r.v;
|
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;
|
end; $$ language plpgsql;
|
||||||
select continue_test1();
|
select continue_test1();
|
||||||
NOTICE: ---1---
|
NOTICE: ---1---
|
||||||
@ -2591,6 +2617,18 @@ NOTICE: 40
|
|||||||
NOTICE: ---6---
|
NOTICE: ---6---
|
||||||
NOTICE: 30
|
NOTICE: 30
|
||||||
NOTICE: 40
|
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
|
continue_test1
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
@ -2170,6 +2170,32 @@ begin
|
|||||||
continue when _r.v <= 20;
|
continue when _r.v <= 20;
|
||||||
raise notice '%', _r.v;
|
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;
|
end; $$ language plpgsql;
|
||||||
|
|
||||||
select continue_test1();
|
select continue_test1();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user