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();
