Hello
Attached patch provide continue stmt in plpgsql language. Continue stmt
start new step in any loop stmt. If stmt continue is in begin end block,
then find first outer loop (per recent discussion).
Regards
Pavel Stehule
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 ----
</sect3>
<sect3>
+ <title><literal>CONTINUE</></title>
+
+ <synopsis>
+ CONTINUE <optional> <replaceable>label</replaceable> </optional> <optional>
WHEN <replaceable>expression</replaceable> </optional>;
+ </synopsis>
+
+ <para>
+ If no <replaceable>label</replaceable> is given,
+ the innermost loop is executed again (if all relevant
+ condition expression evaluates to true). If
<replaceable>label</replaceable>
+ is given, it must be the label of the current or some outer level of
nested loop
+ Then the named loop is evaluated again.
+ </para>
+
+ <para>
+ If <literal>WHEN</> is present, loop continue occurs only if the
specified
+ condition is true, otherwise control passes to the statement after
+ <literal>CONTINUE</>.
+ </para>
+
+ <para>
+ <literal>CONTINUE</> can be used to cause early exit from all types of
+ loops; it is not limited to use with unconditional loops.
+ </para>
+
+ <para>
+ Examples:
+ <programlisting>
+ LOOP
+ -- some computations
+ EXIT WHEN count > 100;
+ CONTINUE WHEN count < 50;
+ -- some computations for count IN [50 .. 100]
+ END LOOP;
+ </programlisting>
+ </para>
+ </sect3>
+
+
+ <sect3>
<title><literal>WHILE</></title>
<synopsis>
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> stmt_dynexecute stmt_getdiag
%type <stmt> stmt_open stmt_fetch stmt_close stmt_null
+ %type <ival> exit_type
+
%type <list> proc_exceptions
%type <exception_block> exception_sect
%type <exception> 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---';
+ <<lbl>>
+ 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---';
+ <<lbl>>
+ 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();
---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to [EMAIL PROTECTED]