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 &gt; 100;
+     CONTINUE WHEN count &lt; 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]

Reply via email to