diff -c -r --new-file pgsql/doc/src/sgml/plpgsql.sgml pgsql.00/doc/src/sgml/plpgsql.sgml
*** pgsql/doc/src/sgml/plpgsql.sgml 2005-06-17 06:53:03.000000000 +0200
--- pgsql.00/doc/src/sgml/plpgsql.sgml 2005-06-17 10:00:15.000000000 +0200
***************
*** 1859,1864 ****
--- 1859,1904 ----
+ CONTINUE>
+
+
+ CONTINUE label WHEN expression ;
+
+
+
+ If no label is given,
+ the innermost loop is executed again (if all relevant
+ condition expression evaluates to true). If label
+ is given, it must be the label of the current or some outer level of nested loop
+ Then the named loop is evaluated again.
+
+
+
+ If WHEN> is present, loop continue occurs only if the specified
+ condition is true, otherwise control passes to the statement after
+ CONTINUE>.
+
+
+
+ CONTINUE> can be used to cause early exit from all types of
+ loops; it is not limited to use with unconditional loops.
+
+
+
+ Examples:
+
+ LOOP
+ -- some computations
+ EXIT WHEN count > 100;
+ CONTINUE WHEN count < 50;
+ -- some computations for count IN [50 .. 100]
+ END LOOP;
+
+
+
+
+
+
WHILE>
diff -c -r --new-file pgsql/src/pl/plpgsql/src/gram.y pgsql.00/src/pl/plpgsql/src/gram.y
*** pgsql/src/pl/plpgsql/src/gram.y 2005-06-17 06:53:56.000000000 +0200
--- pgsql.00/src/pl/plpgsql/src/gram.y 2005-06-17 08:39:10.000000000 +0200
***************
*** 130,135 ****
--- 130,137 ----
%type stmt_dynexecute stmt_getdiag
%type stmt_open stmt_fetch stmt_close stmt_null
+ %type exit_type
+
%type proc_exceptions
%type exception_sect
%type proc_exception
***************
*** 153,158 ****
--- 155,161 ----
%token K_BEGIN
%token K_CLOSE
%token K_CONSTANT
+ %token K_CONTINUE
%token K_CURSOR
%token K_DEBUG
%token K_DECLARE
***************
*** 1035,1046 ****
}
;
! stmt_exit : K_EXIT lno opt_exitlabel opt_exitcond
{
PLpgSQL_stmt_exit *new;
new = palloc0(sizeof(PLpgSQL_stmt_exit));
new->cmd_type = PLPGSQL_STMT_EXIT;
new->lineno = $2;
new->label = $3;
new->cond = $4;
--- 1038,1050 ----
}
;
! stmt_exit : exit_type lno opt_exitlabel opt_exitcond
{
PLpgSQL_stmt_exit *new;
new = palloc0(sizeof(PLpgSQL_stmt_exit));
new->cmd_type = PLPGSQL_STMT_EXIT;
+ new->exit_type = $1;
new->lineno = $2;
new->label = $3;
new->cond = $4;
***************
*** 1049,1054 ****
--- 1053,1068 ----
}
;
+ exit_type : K_EXIT
+ {
+ $$ = 0;
+ }
+ | K_CONTINUE
+ {
+ $$ = 1;
+ }
+ ;
+
stmt_return : K_RETURN lno
{
PLpgSQL_stmt_return *new;
diff -c -r --new-file pgsql/src/pl/plpgsql/src/pl_exec.c pgsql.00/src/pl/plpgsql/src/pl_exec.c
*** pgsql/src/pl/plpgsql/src/pl_exec.c 2005-06-17 06:53:56.000000000 +0200
--- pgsql.00/src/pl/plpgsql/src/pl_exec.c 2005-06-17 09:04:55.000000000 +0200
***************
*** 917,923 ****
{
case PLPGSQL_RC_OK:
return PLPGSQL_RC_OK;
!
case PLPGSQL_RC_EXIT:
if (estate->exitlabel == NULL)
return PLPGSQL_RC_OK;
--- 917,923 ----
{
case PLPGSQL_RC_OK:
return PLPGSQL_RC_OK;
!
case PLPGSQL_RC_EXIT:
if (estate->exitlabel == NULL)
return PLPGSQL_RC_OK;
***************
*** 927,932 ****
--- 927,935 ----
return PLPGSQL_RC_EXIT;
estate->exitlabel = NULL;
return PLPGSQL_RC_OK;
+
+ case PLPGSQL_RC_CONTINUE:
+ return PLPGSQL_RC_CONTINUE;
case PLPGSQL_RC_RETURN:
return PLPGSQL_RC_RETURN;
***************
*** 1210,1215 ****
--- 1213,1228 ----
return PLPGSQL_RC_EXIT;
estate->exitlabel = NULL;
return PLPGSQL_RC_OK;
+
+ case PLPGSQL_RC_CONTINUE:
+ if (estate->exitlabel == NULL)
+ break;
+ if (stmt->label == NULL)
+ return PLPGSQL_RC_CONTINUE;
+ if (strcmp(stmt->label, estate->exitlabel))
+ return PLPGSQL_RC_CONTINUE;
+ estate->exitlabel = NULL;
+ break;
case PLPGSQL_RC_RETURN:
return PLPGSQL_RC_RETURN;
***************
*** 1261,1266 ****
--- 1274,1289 ----
estate->exitlabel = NULL;
return PLPGSQL_RC_OK;
+ case PLPGSQL_RC_CONTINUE:
+ if (estate->exitlabel == NULL)
+ break;
+ if (stmt->label == NULL)
+ return PLPGSQL_RC_CONTINUE;
+ if (strcmp(stmt->label, estate->exitlabel))
+ return PLPGSQL_RC_CONTINUE;
+ estate->exitlabel = NULL;
+ break;
+
case PLPGSQL_RC_RETURN:
return PLPGSQL_RC_RETURN;
***************
*** 1370,1376 ****
--- 1393,1423 ----
break;
}
+ else if (rc == PLPGSQL_RC_CONTINUE)
+ {
+ if (estate->exitlabel == NULL)
+ /* unlabelled continue, continue the current loop */
+ {}
+ else if (stmt->label != NULL &&
+ strcmp(stmt->label, estate->exitlabel) == 0)
+ {
+ /* labelled continue, matches the current stmt's label */
+ estate->exitlabel = NULL;
+ }
+ else
+ {
+ /*
+ * otherwise, we processed a labelled exit that does not match
+ * the current statement's label, if any: return RC_EXIT or RC_CONTINUE so
+ * that the EXIT|CONTINUE continues to recurse upward.
+ */
+ rc = PLPGSQL_RC_CONTINUE;
+ break;
+ }
+
+ }
+
/*
* Increase/decrease loop var
*/
***************
*** 1457,1472 ****
*/
rc = exec_stmts(estate, stmt->body);
if (rc != PLPGSQL_RC_OK)
{
- /*
- * We're aborting the loop, so cleanup and set FOUND.
- * (This code should match the code after the loop.)
- */
- SPI_freetuptable(tuptab);
- SPI_cursor_close(portal);
- exec_set_found(estate, found);
-
if (rc == PLPGSQL_RC_EXIT)
{
if (estate->exitlabel == NULL)
--- 1504,1512 ----
*/
rc = exec_stmts(estate, stmt->body);
+
if (rc != PLPGSQL_RC_OK)
{
if (rc == PLPGSQL_RC_EXIT)
{
if (estate->exitlabel == NULL)
***************
*** 1487,1492 ****
--- 1527,1554 ----
* recurse upward.
*/
}
+ else if (rc == PLPGSQL_RC_CONTINUE)
+ {
+ if (estate->exitlabel == NULL)
+ /* unlabelled continue, continue the current loop */
+ continue;
+ else if (stmt->label != NULL &&
+ strcmp(stmt->label, estate->exitlabel) == 0)
+ {
+ /* labelled continue, matches the current stmt's label */
+ estate->exitlabel = NULL;
+ continue;
+ }
+ rc = PLPGSQL_RC_CONTINUE;
+ }
+
+ /*
+ * We're aborting the loop, so cleanup and set FOUND.
+ * (This code should match the code after the loop.)
+ */
+ SPI_freetuptable(tuptab);
+ SPI_cursor_close(portal);
+ exec_set_found(estate, found);
return rc;
}
***************
*** 1604,1610 ****
}
estate->exitlabel = stmt->label;
! return PLPGSQL_RC_EXIT;
}
--- 1666,1672 ----
}
estate->exitlabel = stmt->label;
! return stmt->exit_type == 0 ? PLPGSQL_RC_EXIT:PLPGSQL_RC_CONTINUE;
}
***************
*** 2433,2446 ****
if (rc != PLPGSQL_RC_OK)
{
- /*
- * We're aborting the loop, so cleanup and set FOUND.
- * (This code should match the code after the loop.)
- */
- SPI_freetuptable(tuptab);
- SPI_cursor_close(portal);
- exec_set_found(estate, found);
-
if (rc == PLPGSQL_RC_EXIT)
{
if (estate->exitlabel == NULL)
--- 2495,2500 ----
***************
*** 2461,2466 ****
--- 2515,2543 ----
* recurse upward.
*/
}
+ else if (rc == PLPGSQL_RC_CONTINUE)
+ {
+ if (estate->exitlabel == NULL)
+ /* unlabelled continue, continue the current loop */
+ continue;
+ else if (stmt->label != NULL &&
+ strcmp(stmt->label, estate->exitlabel) == 0)
+ {
+ /* labelled continue, matches the current stmt's label */
+ estate->exitlabel = NULL;
+ continue;
+ }
+ rc = PLPGSQL_RC_CONTINUE;
+ }
+
+ /*
+ * We're aborting the loop, so cleanup and set FOUND.
+ * (This code should match the code after the loop.)
+ */
+ SPI_freetuptable(tuptab);
+ SPI_cursor_close(portal);
+ exec_set_found(estate, found);
+
return rc;
}
diff -c -r --new-file pgsql/src/pl/plpgsql/src/pl_funcs.c pgsql.00/src/pl/plpgsql/src/pl_funcs.c
*** pgsql/src/pl/plpgsql/src/pl_funcs.c 2005-06-17 06:53:56.000000000 +0200
--- pgsql.00/src/pl/plpgsql/src/pl_funcs.c 2005-06-17 09:38:43.000000000 +0200
***************
*** 845,851 ****
dump_exit(PLpgSQL_stmt_exit *stmt)
{
dump_ind();
! printf("EXIT lbl='%s'", stmt->label);
if (stmt->cond != NULL)
{
printf(" WHEN ");
--- 845,852 ----
dump_exit(PLpgSQL_stmt_exit *stmt)
{
dump_ind();
! printf("%s lbl='%s'", stmt->exit_type == 0? "EXIT":"CONTINUE",
! stmt->label);
if (stmt->cond != NULL)
{
printf(" WHEN ");
diff -c -r --new-file pgsql/src/pl/plpgsql/src/plpgsql.h pgsql.00/src/pl/plpgsql/src/plpgsql.h
*** pgsql/src/pl/plpgsql/src/plpgsql.h 2005-06-17 06:53:56.000000000 +0200
--- pgsql.00/src/pl/plpgsql/src/plpgsql.h 2005-06-17 07:33:34.000000000 +0200
***************
*** 125,131 ****
{
PLPGSQL_RC_OK,
PLPGSQL_RC_EXIT,
! PLPGSQL_RC_RETURN
};
/* ----------
--- 125,132 ----
{
PLPGSQL_RC_OK,
PLPGSQL_RC_EXIT,
! PLPGSQL_RC_RETURN,
! PLPGSQL_RC_CONTINUE
};
/* ----------
***************
*** 488,493 ****
--- 489,495 ----
{ /* EXIT statement */
int cmd_type;
int lineno;
+ int exit_type; /* exit or continue */
char *label;
PLpgSQL_expr *cond;
} PLpgSQL_stmt_exit;
diff -c -r --new-file pgsql/src/pl/plpgsql/src/scan.l pgsql.00/src/pl/plpgsql/src/scan.l
*** pgsql/src/pl/plpgsql/src/scan.l 2005-06-17 06:53:56.000000000 +0200
--- pgsql.00/src/pl/plpgsql/src/scan.l 2005-06-17 07:16:33.000000000 +0200
***************
*** 139,144 ****
--- 139,145 ----
begin { return K_BEGIN; }
close { return K_CLOSE; }
constant { return K_CONSTANT; }
+ continue { return K_CONTINUE; }
cursor { return K_CURSOR; }
debug { return K_DEBUG; }
declare { return K_DECLARE; }
diff -c -r --new-file pgsql/src/test/regress/expected/plpgsql.out pgsql.00/src/test/regress/expected/plpgsql.out
*** pgsql/src/test/regress/expected/plpgsql.out 2005-06-17 06:54:08.000000000 +0200
--- pgsql.00/src/test/regress/expected/plpgsql.out 2005-06-17 09:46:06.000000000 +0200
***************
*** 2491,2493 ****
--- 2491,2603 ----
(1 row)
drop function raise_exprs();
+
+ -- continue statement
+ create table conttesttbl(idx serial, v integer);
+ NOTICE: CREATE TABLE will create implicit sequence "conttesttbl_idx_seq" for serial column "conttesttbl.idx"
+ CREATE TABLE
+ insert into conttesttbl(v) values(10);
+ INSERT 0 1
+ insert into conttesttbl(v) values(20);
+ INSERT 0 1
+ insert into conttesttbl(v) values(30);
+ INSERT 0 1
+ insert into conttesttbl(v) values(40);
+ INSERT 0 1
+ create or replace function conttest() returns void as $$
+ declare _i integer = 0; _r record;
+ begin
+ raise notice '---1---';
+ loop
+ _i := _i + 1;
+ raise notice '%', _i;
+ continue when _i < 10;
+ exit;
+ end loop;
+ raise notice '---2---';
+ <>
+ loop
+ _i := _i - 1;
+ loop
+ raise notice '%', _i;
+ continue lbl when _i > 0;
+ exit lbl;
+ end loop;
+ end loop;
+ raise notice '---3---';
+ while _i < 10 loop
+ _i := _i + 1;
+ continue when _i % 2 = 0;
+ raise notice '%', _i;
+ end loop;
+ raise notice '---4---';
+ for _i in 1..10 loop
+ begin
+ -- finfing outer loop
+ continue when _i < 5;
+ raise notice '%', _i;
+ end;
+ end loop;
+ raise notice '---5---';
+ for _r in select * from conttesttbl loop
+ continue when _r.v <= 20;
+ raise notice '%', _r.v;
+ end loop;
+ raise notice '---6---';
+ for _r in execute 'select * from conttesttbl' loop
+ continue when _r.v <= 20;
+ raise notice '%', _r.v;
+ end loop;
+ end; $$ language plpgsql;
+ CREATE FUNCTION
+ select conttest();
+ NOTICE: ---1---
+ NOTICE: 1
+ NOTICE: 2
+ NOTICE: 3
+ NOTICE: 4
+ NOTICE: 5
+ NOTICE: 6
+ NOTICE: 7
+ NOTICE: 8
+ NOTICE: 9
+ NOTICE: 10
+ NOTICE: ---2---
+ NOTICE: 9
+ NOTICE: 8
+ NOTICE: 7
+ NOTICE: 6
+ NOTICE: 5
+ NOTICE: 4
+ NOTICE: 3
+ NOTICE: 2
+ NOTICE: 1
+ NOTICE: 0
+ NOTICE: ---3---
+ NOTICE: 1
+ NOTICE: 3
+ NOTICE: 5
+ NOTICE: 7
+ NOTICE: 9
+ NOTICE: ---4---
+ NOTICE: 5
+ NOTICE: 6
+ NOTICE: 7
+ NOTICE: 8
+ NOTICE: 9
+ NOTICE: 10
+ NOTICE: ---5---
+ NOTICE: 30
+ NOTICE: 40
+ NOTICE: ---6---
+ NOTICE: 30
+ NOTICE: 40
+ conttest
+ ----------
+
+ (1 row)
+
+ drop table conttesttbl;
+ DROP TABLE
+ drop function conttest();
+ DROP FUNCTION
diff -c -r --new-file pgsql/src/test/regress/sql/plpgsql.sql pgsql.00/src/test/regress/sql/plpgsql.sql
*** pgsql/src/test/regress/sql/plpgsql.sql 2005-06-17 06:54:06.000000000 +0200
--- pgsql.00/src/test/regress/sql/plpgsql.sql 2005-06-17 09:44:48.000000000 +0200
***************
*** 2112,2114 ****
--- 2112,2172 ----
select raise_exprs();
drop function raise_exprs();
+
+ -- continue statement
+ create table conttesttbl(idx serial, v integer);
+ insert into conttesttbl(v) values(10);
+ insert into conttesttbl(v) values(20);
+ insert into conttesttbl(v) values(30);
+ insert into conttesttbl(v) values(40);
+
+
+ create or replace function conttest() returns void as $$
+ declare _i integer = 0; _r record;
+ begin
+ raise notice '---1---';
+ loop
+ _i := _i + 1;
+ raise notice '%', _i;
+ continue when _i < 10;
+ exit;
+ end loop;
+ raise notice '---2---';
+ <>
+ loop
+ _i := _i - 1;
+ loop
+ raise notice '%', _i;
+ continue lbl when _i > 0;
+ exit lbl;
+ end loop;
+ end loop;
+ raise notice '---3---';
+ while _i < 10 loop
+ _i := _i + 1;
+ continue when _i % 2 = 0;
+ raise notice '%', _i;
+ end loop;
+ raise notice '---4---';
+ for _i in 1..10 loop
+ begin
+ -- finfing outer loop
+ continue when _i < 5;
+ raise notice '%', _i;
+ end;
+ end loop;
+ raise notice '---5---';
+ for _r in select * from conttesttbl loop
+ continue when _r.v <= 20;
+ raise notice '%', _r.v;
+ end loop;
+ raise notice '---6---';
+ for _r in execute 'select * from conttesttbl' loop
+ continue when _r.v <= 20;
+ raise notice '%', _r.v;
+ end loop;
+ end; $$ language plpgsql;
+ select conttest();
+
+ drop table conttesttbl;
+ drop function conttest();