diff --git a/src/pl/plpgsql/src/expected/plpgsql_control.out b/src/pl/plpgsql/src/expected/plpgsql_control.out
index b7089e3..73b23a3 100644
*** a/src/pl/plpgsql/src/expected/plpgsql_control.out
--- b/src/pl/plpgsql/src/expected/plpgsql_control.out
*************** begin
*** 413,449 ****
    raise notice 'should get here';
  end$$;
  NOTICE:  should get here
- -- check exit to a matching outer loop (other cases are covered elsewhere)
- do $$
- begin
- <<outerloop>>
- for i in 1..10 loop
-   <<innerloop>>
-   for j in 1..10 loop
-     exit outerloop;
-     raise notice 'should not get here';
-   end loop;
-   raise notice 'should not get here, either';
- end loop;
- raise notice 'should get here';
- end$$;
- NOTICE:  should get here
- -- return out of a loop
- create function return_from_loop() returns int language plpgsql as $$
- begin
-   for i in 1..10 loop
-     if i > 3 then
-       return i;
-     end if;
-   end loop;
-   return null;
- end$$;
- select return_from_loop();
-  return_from_loop 
- ------------------
-                 4
- (1 row)
- 
  -- unlabeled exit does match a while loop
  do $$
  begin
--- 413,418 ----
*************** select return_from_while();
*** 522,657 ****
                   3
  (1 row)
  
- -- exit out of a foreach
- do $$
- declare i int; j int; k int;
- begin
-   <<outermostforeach>>
-   foreach i in array array[1,2,3] loop
-     <<outerforeach>>
-     foreach j in array array[1,2,3] loop
-       <<innerforeach>>
-       foreach k in array array[1,2,3] loop
-         exit;
-         raise notice 'should not get here';
-       end loop;
-       raise notice 'should get here';
-       exit outermostforeach;
-       raise notice 'should not get here, either';
-     end loop;
-     raise notice 'nor here';
-   end loop;
-   raise notice 'should get here, too';
- end$$;
- NOTICE:  should get here
- NOTICE:  should get here, too
- -- continue out of a foreach
- do $$
- declare i int; j int; k int;
- begin
-   <<outermostforeach>>
-   foreach i in array array[1,2,3] loop
-     <<outerforeach>>
-     foreach j in array array[1,2,3] loop
-       <<innerforeach>>
-       foreach k in array array[1,2,3] loop
-         continue;
-         raise notice 'should not get here';
-       end loop;
-       raise notice 'should get here, k = %', k;
-       continue outermostforeach;
-       raise notice 'should not get here, either';
-     end loop;
-     raise notice 'nor here';
-   end loop;
-   raise notice 'should get here, i = %, j = %, k = %', i, j, k;
- end$$;
- NOTICE:  should get here, k = 3
- NOTICE:  should get here, k = 3
- NOTICE:  should get here, k = 3
- NOTICE:  should get here, i = 3, j = 1, k = 3
- -- return out of a foreach
- create function return_from_foreach() returns int language plpgsql as $$
- declare i int := 0;
- begin
-   foreach i in array array[1,2,3] loop
-     if i > 1 then
-       return i;
-     end if;
-   end loop;
-   return null;
- end$$;
- select return_from_foreach();
-  return_from_foreach 
- ---------------------
-                    2
- (1 row)
- 
- -- exit out of a for-over-query
- do $$
- declare i int; j int; k int;
- begin
-   <<outermostfor>>
-   for i in select generate_series(1,3) loop
-     <<outerfor>>
-     for j in select generate_series(1,3) loop
-       <<innerfor>>
-       for k in select generate_series(1,3) loop
-         exit;
-         raise notice 'should not get here';
-       end loop;
-       raise notice 'should get here';
-       exit outermostfor;
-       raise notice 'should not get here, either';
-     end loop;
-     raise notice 'nor here';
-   end loop;
-   raise notice 'should get here, too';
- end$$;
- NOTICE:  should get here
- NOTICE:  should get here, too
- -- continue out of a for-over-query
- do $$
- declare i int; j int; k int;
- begin
-   <<outermostfor>>
-   for i in select generate_series(1,3) loop
-     <<outerfor>>
-     for j in select generate_series(1,3) loop
-       <<innerfor>>
-       for k in select generate_series(1,3) loop
-         continue;
-         raise notice 'should not get here';
-       end loop;
-       raise notice 'should get here, k = %', k;
-       continue outermostfor;
-       raise notice 'should not get here, either';
-     end loop;
-     raise notice 'nor here';
-   end loop;
-   raise notice 'should get here, i = %, j = %, k = %', i, j, k;
- end$$;
- NOTICE:  should get here, k = 3
- NOTICE:  should get here, k = 3
- NOTICE:  should get here, k = 3
- NOTICE:  should get here, i = 3, j = 1, k = 3
- -- return out of a for-over-query
- create function return_from_for_query() returns int language plpgsql as $$
- declare i int := 0;
- begin
-   for i in select generate_series(1,3) loop
-     if i > 1 then
-       return i;
-     end if;
-   end loop;
-   return null;
- end$$;
- select return_from_for_query();
-  return_from_for_query 
- -----------------------
-                      2
- (1 row)
- 
  -- using list of scalars in fori and fore stmts
  create function for_vect() returns void as $proc$
  <<lbl>>declare a integer; b varchar; c varchar; r record;
--- 491,496 ----
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index dd575e7..a05a52a 100644
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
*************** typedef struct					/* cast_hash table en
*** 155,160 ****
--- 155,234 ----
  static MemoryContext shared_cast_context = NULL;
  static HTAB *shared_cast_hash = NULL;
  
+ /*
+  * LOOP_RC_PROCESSING encapsulates common logic for looping statements to
+  * handle return/exit/continue result codes from the loop body statement(s).
+  * It's meant to be used like this:
+  *
+  *		int rc = PLPGSQL_RC_OK;
+  *		for (...)
+  *		{
+  *			...
+  *			rc = exec_stmts(estate, stmt->body);
+  *			LOOP_RC_PROCESSING(stmt->label);
+  *			...
+  *		}
+  *		return rc;
+  *
+  * If execution of the loop should terminate, LOOP_RC_PROCESSING will execute
+  * a "break", after updating "rc" if necessary to the value the current
+  * statement should return.  If execution should continue, LOOP_RC_PROCESSING
+  * will do nothing except reset "rc" to PLPGSQL_RC_OK.
+  *
+  * estate and rc are implicit arguments to the macro.
+  * estate->exitlabel is examined and possibly updated.
+  */
+ #define LOOP_RC_PROCESSING(looplabel) \
+ 	if (rc == PLPGSQL_RC_RETURN) \
+ 	{ \
+ 		/* RETURN, so propagate RC_RETURN out */ \
+ 		break; \
+ 	} \
+ 	else if (rc == PLPGSQL_RC_EXIT) \
+ 	{ \
+ 		if (estate->exitlabel == NULL) \
+ 		{ \
+ 			/* unlabelled EXIT terminates this loop */ \
+ 			rc = PLPGSQL_RC_OK; \
+ 			break; \
+ 		} \
+ 		else if ((looplabel) != NULL && \
+ 				 strcmp(looplabel, estate->exitlabel) == 0) \
+ 		{ \
+ 			/* labelled EXIT matching this loop, so terminate loop */ \
+ 			estate->exitlabel = NULL; \
+ 			rc = PLPGSQL_RC_OK; \
+ 			break; \
+ 		} \
+ 		else \
+ 		{ \
+ 			/* non-matching labelled EXIT, propagate RC_EXIT out */ \
+ 			break; \
+ 		} \
+ 	} \
+ 	else if (rc == PLPGSQL_RC_CONTINUE) \
+ 	{ \
+ 		if (estate->exitlabel == NULL) \
+ 		{ \
+ 			/* unlabelled CONTINUE matches this loop, so continue in loop */ \
+ 			rc = PLPGSQL_RC_OK; \
+ 		} \
+ 		else if ((looplabel) != NULL && \
+ 				 strcmp(looplabel, estate->exitlabel) == 0) \
+ 		{ \
+ 			/* labelled CONTINUE matching this loop, so continue in loop */ \
+ 			estate->exitlabel = NULL; \
+ 			rc = PLPGSQL_RC_OK; \
+ 		} \
+ 		else \
+ 		{ \
+ 			/* non-matching labelled CONTINUE, propagate RC_CONTINUE out */ \
+ 			break; \
+ 		} \
+ 	} \
+ 	else \
+ 		Assert(rc == PLPGSQL_RC_OK)
+ 
  /************************************************************
   * Local function forward declarations
   ************************************************************/
*************** exec_stmt_block(PLpgSQL_execstate *estat
*** 1476,1482 ****
  	estate->err_text = NULL;
  
  	/*
! 	 * Handle the return code.
  	 */
  	switch (rc)
  	{
--- 1550,1558 ----
  	estate->err_text = NULL;
  
  	/*
! 	 * Handle the return code.  This is intentionally different from
! 	 * LOOP_RC_PROCESSING(): CONTINUE never matches a block, and EXIT matches
! 	 * a block only if there is a label match.
  	 */
  	switch (rc)
  	{
*************** exec_stmt_block(PLpgSQL_execstate *estat
*** 1486,1496 ****
  			return rc;
  
  		case PLPGSQL_RC_EXIT:
- 
- 			/*
- 			 * This is intentionally different from the handling of RC_EXIT
- 			 * for loops: to match a block, we require a match by label.
- 			 */
  			if (estate->exitlabel == NULL)
  				return PLPGSQL_RC_EXIT;
  			if (block->label == NULL)
--- 1562,1567 ----
*************** exec_stmt_case(PLpgSQL_execstate *estate
*** 1948,1992 ****
  static int
  exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
  {
  	for (;;)
  	{
! 		int			rc = exec_stmts(estate, stmt->body);
! 
! 		switch (rc)
! 		{
! 			case PLPGSQL_RC_OK:
! 				break;
! 
! 			case PLPGSQL_RC_EXIT:
! 				if (estate->exitlabel == NULL)
! 					return PLPGSQL_RC_OK;
! 				if (stmt->label == NULL)
! 					return PLPGSQL_RC_EXIT;
! 				if (strcmp(stmt->label, estate->exitlabel) != 0)
! 					return PLPGSQL_RC_EXIT;
! 				estate->exitlabel = NULL;
! 				return PLPGSQL_RC_OK;
! 
! 			case PLPGSQL_RC_CONTINUE:
! 				if (estate->exitlabel == NULL)
! 					/* anonymous continue, so re-run the loop */
! 					break;
! 				else if (stmt->label != NULL &&
! 						 strcmp(stmt->label, estate->exitlabel) == 0)
! 					/* label matches named continue, so re-run loop */
! 					estate->exitlabel = NULL;
! 				else
! 					/* label doesn't match named continue, so propagate upward */
! 					return PLPGSQL_RC_CONTINUE;
! 				break;
! 
! 			case PLPGSQL_RC_RETURN:
! 				return rc;
  
! 			default:
! 				elog(ERROR, "unrecognized rc: %d", rc);
! 		}
  	}
  }
  
  
--- 2019,2034 ----
  static int
  exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
  {
+ 	int			rc = PLPGSQL_RC_OK;
+ 
  	for (;;)
  	{
! 		rc = exec_stmts(estate, stmt->body);
  
! 		LOOP_RC_PROCESSING(stmt->label);
  	}
+ 
+ 	return rc;
  }
  
  
*************** exec_stmt_loop(PLpgSQL_execstate *estate
*** 1999,2007 ****
  static int
  exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
  {
  	for (;;)
  	{
- 		int			rc;
  		bool		value;
  		bool		isnull;
  
--- 2041,2050 ----
  static int
  exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
  {
+ 	int			rc = PLPGSQL_RC_OK;
+ 
  	for (;;)
  	{
  		bool		value;
  		bool		isnull;
  
*************** exec_stmt_while(PLpgSQL_execstate *estat
*** 2013,2055 ****
  
  		rc = exec_stmts(estate, stmt->body);
  
! 		switch (rc)
! 		{
! 			case PLPGSQL_RC_OK:
! 				break;
! 
! 			case PLPGSQL_RC_EXIT:
! 				if (estate->exitlabel == NULL)
! 					return PLPGSQL_RC_OK;
! 				if (stmt->label == NULL)
! 					return PLPGSQL_RC_EXIT;
! 				if (strcmp(stmt->label, estate->exitlabel) != 0)
! 					return PLPGSQL_RC_EXIT;
! 				estate->exitlabel = NULL;
! 				return PLPGSQL_RC_OK;
! 
! 			case PLPGSQL_RC_CONTINUE:
! 				if (estate->exitlabel == NULL)
! 					/* anonymous continue, so re-run loop */
! 					break;
! 				else if (stmt->label != NULL &&
! 						 strcmp(stmt->label, estate->exitlabel) == 0)
! 					/* label matches named continue, so re-run loop */
! 					estate->exitlabel = NULL;
! 				else
! 					/* label doesn't match named continue, propagate upward */
! 					return PLPGSQL_RC_CONTINUE;
! 				break;
! 
! 			case PLPGSQL_RC_RETURN:
! 				return rc;
! 
! 			default:
! 				elog(ERROR, "unrecognized rc: %d", rc);
! 		}
  	}
  
! 	return PLPGSQL_RC_OK;
  }
  
  
--- 2056,2065 ----
  
  		rc = exec_stmts(estate, stmt->body);
  
! 		LOOP_RC_PROCESSING(stmt->label);
  	}
  
! 	return rc;
  }
  
  
*************** exec_stmt_fori(PLpgSQL_execstate *estate
*** 2163,2212 ****
  		 */
  		rc = exec_stmts(estate, stmt->body);
  
! 		if (rc == PLPGSQL_RC_RETURN)
! 			break;				/* break out of the loop */
! 		else if (rc == PLPGSQL_RC_EXIT)
! 		{
! 			if (estate->exitlabel == NULL)
! 				/* unlabelled exit, finish the current loop */
! 				rc = PLPGSQL_RC_OK;
! 			else if (stmt->label != NULL &&
! 					 strcmp(stmt->label, estate->exitlabel) == 0)
! 			{
! 				/* labelled exit, matches the current stmt's label */
! 				estate->exitlabel = NULL;
! 				rc = PLPGSQL_RC_OK;
! 			}
! 
! 			/*
! 			 * otherwise, this is a labelled exit that does not match the
! 			 * current statement's label, if any: return RC_EXIT so that the
! 			 * EXIT continues to propagate up the stack.
! 			 */
! 			break;
! 		}
! 		else if (rc == PLPGSQL_RC_CONTINUE)
! 		{
! 			if (estate->exitlabel == NULL)
! 				/* unlabelled continue, so re-run the current loop */
! 				rc = PLPGSQL_RC_OK;
! 			else if (stmt->label != NULL &&
! 					 strcmp(stmt->label, estate->exitlabel) == 0)
! 			{
! 				/* label matches named continue, so re-run loop */
! 				estate->exitlabel = NULL;
! 				rc = PLPGSQL_RC_OK;
! 			}
! 			else
! 			{
! 				/*
! 				 * otherwise, this is a named continue that does not match the
! 				 * current statement's label, if any: return RC_CONTINUE so
! 				 * that the CONTINUE will propagate up the stack.
! 				 */
! 				break;
! 			}
! 		}
  
  		/*
  		 * Increase/decrease loop value, unless it would overflow, in which
--- 2173,2179 ----
  		 */
  		rc = exec_stmts(estate, stmt->body);
  
! 		LOOP_RC_PROCESSING(stmt->label);
  
  		/*
  		 * Increase/decrease loop value, unless it would overflow, in which
*************** exec_stmt_foreach_a(PLpgSQL_execstate *e
*** 2536,2586 ****
  		 */
  		rc = exec_stmts(estate, stmt->body);
  
! 		/* Handle the return code */
! 		if (rc == PLPGSQL_RC_RETURN)
! 			break;				/* break out of the loop */
! 		else if (rc == PLPGSQL_RC_EXIT)
! 		{
! 			if (estate->exitlabel == NULL)
! 				/* unlabelled exit, finish the current loop */
! 				rc = PLPGSQL_RC_OK;
! 			else if (stmt->label != NULL &&
! 					 strcmp(stmt->label, estate->exitlabel) == 0)
! 			{
! 				/* labelled exit, matches the current stmt's label */
! 				estate->exitlabel = NULL;
! 				rc = PLPGSQL_RC_OK;
! 			}
! 
! 			/*
! 			 * otherwise, this is a labelled exit that does not match the
! 			 * current statement's label, if any: return RC_EXIT so that the
! 			 * EXIT continues to propagate up the stack.
! 			 */
! 			break;
! 		}
! 		else if (rc == PLPGSQL_RC_CONTINUE)
! 		{
! 			if (estate->exitlabel == NULL)
! 				/* unlabelled continue, so re-run the current loop */
! 				rc = PLPGSQL_RC_OK;
! 			else if (stmt->label != NULL &&
! 					 strcmp(stmt->label, estate->exitlabel) == 0)
! 			{
! 				/* label matches named continue, so re-run loop */
! 				estate->exitlabel = NULL;
! 				rc = PLPGSQL_RC_OK;
! 			}
! 			else
! 			{
! 				/*
! 				 * otherwise, this is a named continue that does not match the
! 				 * current statement's label, if any: return RC_CONTINUE so
! 				 * that the CONTINUE will propagate up the stack.
! 				 */
! 				break;
! 			}
! 		}
  
  		MemoryContextSwitchTo(stmt_mcontext);
  	}
--- 2503,2509 ----
  		 */
  		rc = exec_stmts(estate, stmt->body);
  
! 		LOOP_RC_PROCESSING(stmt->label);
  
  		MemoryContextSwitchTo(stmt_mcontext);
  	}
*************** exec_for_query(PLpgSQL_execstate *estate
*** 5330,5335 ****
--- 5253,5259 ----
  	bool		found = false;
  	int			rc = PLPGSQL_RC_OK;
  	uint64		n;
+ 	uint64		i;
  
  	/* Fetch loop variable's datum entry */
  	var = (PLpgSQL_variable *) estate->datums[stmt->var->dno];
*************** exec_for_query(PLpgSQL_execstate *estate
*** 5364,5454 ****
  	/*
  	 * Now do the loop
  	 */
! 	while (n > 0)
  	{
! 		uint64		i;
! 
! 		for (i = 0; i < n; i++)
! 		{
! 			/*
! 			 * Assign the tuple to the target
! 			 */
! 			exec_move_row(estate, var, tuptab->vals[i], tuptab->tupdesc);
! 			exec_eval_cleanup(estate);
! 
! 			/*
! 			 * Execute the statements
! 			 */
! 			rc = exec_stmts(estate, stmt->body);
! 
! 			if (rc != PLPGSQL_RC_OK)
! 			{
! 				if (rc == PLPGSQL_RC_EXIT)
! 				{
! 					if (estate->exitlabel == NULL)
! 					{
! 						/* unlabelled exit, so exit the current loop */
! 						rc = PLPGSQL_RC_OK;
! 					}
! 					else if (stmt->label != NULL &&
! 							 strcmp(stmt->label, estate->exitlabel) == 0)
! 					{
! 						/* label matches this loop, so exit loop */
! 						estate->exitlabel = NULL;
! 						rc = PLPGSQL_RC_OK;
! 					}
! 
! 					/*
! 					 * otherwise, we processed a labelled exit that does not
! 					 * match the current statement's label, if any; return
! 					 * RC_EXIT so that the EXIT continues to recurse upward.
! 					 */
! 				}
! 				else if (rc == PLPGSQL_RC_CONTINUE)
! 				{
! 					if (estate->exitlabel == NULL)
! 					{
! 						/* unlabelled continue, so re-run the current loop */
! 						rc = PLPGSQL_RC_OK;
! 						continue;
! 					}
! 					else if (stmt->label != NULL &&
! 							 strcmp(stmt->label, estate->exitlabel) == 0)
! 					{
! 						/* label matches this loop, so re-run loop */
! 						estate->exitlabel = NULL;
! 						rc = PLPGSQL_RC_OK;
! 						continue;
! 					}
! 
! 					/*
! 					 * otherwise, we process a labelled continue that does not
! 					 * match the current statement's label, if any; return
! 					 * RC_CONTINUE so that the CONTINUE will propagate up the
! 					 * stack.
! 					 */
! 				}
  
! 				/*
! 				 * We're aborting the loop.  Need a goto to get out of two
! 				 * levels of loop...
! 				 */
! 				goto loop_exit;
! 			}
! 		}
  
! 		SPI_freetuptable(tuptab);
  
  		/*
! 		 * Fetch more tuples.  If prefetching is allowed, grab 50 at a time.
  		 */
! 		SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
! 		tuptab = SPI_tuptable;
! 		n = SPI_processed;
  	}
  
- loop_exit:
- 
  	/*
  	 * Release last group of tuples (if any)
  	 */
--- 5288,5324 ----
  	/*
  	 * Now do the loop
  	 */
! 	i = 0;
! 	while (i < n)
  	{
! 		/*
! 		 * Assign the tuple to the target
! 		 */
! 		exec_move_row(estate, var, tuptab->vals[i], tuptab->tupdesc);
! 		exec_eval_cleanup(estate);
  
! 		/*
! 		 * Execute the statements
! 		 */
! 		rc = exec_stmts(estate, stmt->body);
  
! 		LOOP_RC_PROCESSING(stmt->label);
  
  		/*
! 		 * Advance to next tuple in current tuptab, if there is one.
! 		 * Otherwise, fetch more tuples.
  		 */
! 		if (++i >= n)
! 		{
! 			SPI_freetuptable(tuptab);
! 			/* If prefetching is allowed, grab 50 at a time. */
! 			SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
! 			tuptab = SPI_tuptable;
! 			n = SPI_processed;
! 			i = 0;
! 		}
  	}
  
  	/*
  	 * Release last group of tuples (if any)
  	 */
diff --git a/src/pl/plpgsql/src/sql/plpgsql_control.sql b/src/pl/plpgsql/src/sql/plpgsql_control.sql
index 2a9dfa9..61d6ca6 100644
*** a/src/pl/plpgsql/src/sql/plpgsql_control.sql
--- b/src/pl/plpgsql/src/sql/plpgsql_control.sql
*************** begin
*** 311,344 ****
    raise notice 'should get here';
  end$$;
  
- -- check exit to a matching outer loop (other cases are covered elsewhere)
- do $$
- begin
- <<outerloop>>
- for i in 1..10 loop
-   <<innerloop>>
-   for j in 1..10 loop
-     exit outerloop;
-     raise notice 'should not get here';
-   end loop;
-   raise notice 'should not get here, either';
- end loop;
- raise notice 'should get here';
- end$$;
- 
- -- return out of a loop
- create function return_from_loop() returns int language plpgsql as $$
- begin
-   for i in 1..10 loop
-     if i > 3 then
-       return i;
-     end if;
-   end loop;
-   return null;
- end$$;
- 
- select return_from_loop();
- 
  -- unlabeled exit does match a while loop
  do $$
  begin
--- 311,316 ----
*************** end$$;
*** 411,532 ****
  
  select return_from_while();
  
- -- exit out of a foreach
- do $$
- declare i int; j int; k int;
- begin
-   <<outermostforeach>>
-   foreach i in array array[1,2,3] loop
-     <<outerforeach>>
-     foreach j in array array[1,2,3] loop
-       <<innerforeach>>
-       foreach k in array array[1,2,3] loop
-         exit;
-         raise notice 'should not get here';
-       end loop;
-       raise notice 'should get here';
-       exit outermostforeach;
-       raise notice 'should not get here, either';
-     end loop;
-     raise notice 'nor here';
-   end loop;
-   raise notice 'should get here, too';
- end$$;
- 
- -- continue out of a foreach
- do $$
- declare i int; j int; k int;
- begin
-   <<outermostforeach>>
-   foreach i in array array[1,2,3] loop
-     <<outerforeach>>
-     foreach j in array array[1,2,3] loop
-       <<innerforeach>>
-       foreach k in array array[1,2,3] loop
-         continue;
-         raise notice 'should not get here';
-       end loop;
-       raise notice 'should get here, k = %', k;
-       continue outermostforeach;
-       raise notice 'should not get here, either';
-     end loop;
-     raise notice 'nor here';
-   end loop;
-   raise notice 'should get here, i = %, j = %, k = %', i, j, k;
- end$$;
- 
- -- return out of a foreach
- create function return_from_foreach() returns int language plpgsql as $$
- declare i int := 0;
- begin
-   foreach i in array array[1,2,3] loop
-     if i > 1 then
-       return i;
-     end if;
-   end loop;
-   return null;
- end$$;
- 
- select return_from_foreach();
- 
- -- exit out of a for-over-query
- do $$
- declare i int; j int; k int;
- begin
-   <<outermostfor>>
-   for i in select generate_series(1,3) loop
-     <<outerfor>>
-     for j in select generate_series(1,3) loop
-       <<innerfor>>
-       for k in select generate_series(1,3) loop
-         exit;
-         raise notice 'should not get here';
-       end loop;
-       raise notice 'should get here';
-       exit outermostfor;
-       raise notice 'should not get here, either';
-     end loop;
-     raise notice 'nor here';
-   end loop;
-   raise notice 'should get here, too';
- end$$;
- 
- -- continue out of a for-over-query
- do $$
- declare i int; j int; k int;
- begin
-   <<outermostfor>>
-   for i in select generate_series(1,3) loop
-     <<outerfor>>
-     for j in select generate_series(1,3) loop
-       <<innerfor>>
-       for k in select generate_series(1,3) loop
-         continue;
-         raise notice 'should not get here';
-       end loop;
-       raise notice 'should get here, k = %', k;
-       continue outermostfor;
-       raise notice 'should not get here, either';
-     end loop;
-     raise notice 'nor here';
-   end loop;
-   raise notice 'should get here, i = %, j = %, k = %', i, j, k;
- end$$;
- 
- -- return out of a for-over-query
- create function return_from_for_query() returns int language plpgsql as $$
- declare i int := 0;
- begin
-   for i in select generate_series(1,3) loop
-     if i > 1 then
-       return i;
-     end if;
-   end loop;
-   return null;
- end$$;
- 
- select return_from_for_query();
- 
  -- using list of scalars in fori and fore stmts
  create function for_vect() returns void as $proc$
  <<lbl>>declare a integer; b varchar; c varchar; r record;
--- 383,388 ----
