提交 ebcb4c93 编写于 作者: N Neil Conway

Add a CONTINUE statement to PL/PgSQL, which can be used to begin the

next iteration of a loop. Update documentation and add regression tests.
Patch from Pavel Stehule, reviewed by Neil Conway.
上级 7a28de20
<!--
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.73 2005/06/19 23:39:05 neilc Exp $
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.74 2005/06/22 01:35:02 neilc Exp $
-->
<chapter id="plpgsql">
......@@ -1779,10 +1779,10 @@ END IF;
</indexterm>
<para>
With the <literal>LOOP</>, <literal>EXIT</>, <literal>WHILE</>,
and <literal>FOR</> statements, you can arrange for your
<application>PL/pgSQL</application> function to repeat a series
of commands.
With the <literal>LOOP</>, <literal>EXIT</>,
<literal>CONTINUE</>, <literal>WHILE</>, and <literal>FOR</>
statements, you can arrange for your <application>PL/pgSQL</>
function to repeat a series of commands.
</para>
<sect3>
......@@ -1807,30 +1807,36 @@ END LOOP;
<sect3>
<title><literal>EXIT</></title>
<indexterm>
<primary>EXIT</primary>
<secondary>in PL/pgSQL</secondary>
</indexterm>
<synopsis>
EXIT <optional> <replaceable>label</replaceable> </optional> <optional> WHEN <replaceable>expression</replaceable> </optional>;
</synopsis>
<para>
If no <replaceable>label</replaceable> is given,
the innermost loop is terminated and the
statement following <literal>END LOOP</> is executed next.
If <replaceable>label</replaceable> is given, it
must be the label of the current or some outer level of nested loop
or block. Then the named loop or block is terminated and control
continues with the statement after the loop's/block's corresponding
<literal>END</>.
If no <replaceable>label</replaceable> is given, the innermost
loop is terminated and the statement following <literal>END
LOOP</> is executed next. If <replaceable>label</replaceable>
is given, it must be the label of the current or some outer
level of nested loop or block. Then the named loop or block is
terminated and control continues with the statement after the
loop's/block's corresponding <literal>END</>.
</para>
<para>
If <literal>WHEN</> is present, loop exit occurs only if the specified
condition is true, otherwise control passes to the statement after
<literal>EXIT</>.
If <literal>WHEN</> is specified, the loop exit occurs only if
<replaceable>expression</> is true. Otherwise, control passes
to the statement after <literal>EXIT</>.
</para>
<para>
<literal>EXIT</> can be used to cause early exit from all types of
loops; it is not limited to use with unconditional loops.
<literal>EXIT</> can be used with all types of loops; it is
not limited to use with unconditional loops. When used with a
<literal>BEGIN</literal> block, <literal>EXIT</literal> passes
control to the next statement after the end of the block.
</para>
<para>
......@@ -1858,9 +1864,61 @@ END;
</para>
</sect3>
<sect3>
<title><literal>CONTINUE</></title>
<indexterm>
<primary>CONTINUE</primary>
<secondary>in PL/pgSQL</secondary>
</indexterm>
<synopsis>
CONTINUE <optional> <replaceable>label</replaceable> </optional> <optional> WHEN <replaceable>expression</replaceable> </optional>;
</synopsis>
<para>
If no <replaceable>label</> is given, the next iteration of
the innermost loop is begun. That is, control is passed back
to the loop control expression (if any), and the body of the
loop is re-evaluated. If <replaceable>label</> is present, it
specifies the label of the loop whose execution will be
continued.
</para>
<para>
If <literal>WHEN</> is specified, the next iteration of the
loop is begun only if <replaceable>expression</> is
true. Otherwise, control passes to the statement after
<literal>CONTINUE</>.
</para>
<para>
<literal>CONTINUE</> can be used with 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>
<indexterm>
<primary>WHILE</primary>
<secondary>in PL/pgSQL</secondary>
</indexterm>
<synopsis>
<optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
WHILE <replaceable>expression</replaceable> LOOP
......
......@@ -4,7 +4,7 @@
* procedural language
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.76 2005/06/14 06:43:14 neilc Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.77 2005/06/22 01:35:02 neilc Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
......@@ -61,6 +61,7 @@ static void plpgsql_sql_error_callback(void *arg);
%union {
int32 ival;
bool boolean;
char *str;
struct
{
......@@ -100,7 +101,7 @@ static void plpgsql_sql_error_callback(void *arg);
%type <declhdr> decl_sect
%type <varname> decl_varname
%type <str> decl_renname
%type <ival> decl_const decl_notnull
%type <boolean> decl_const decl_notnull exit_type
%type <expr> decl_defval decl_cursor_query
%type <dtype> decl_datatype
%type <row> decl_cursor_args
......@@ -153,6 +154,7 @@ static void plpgsql_sql_error_callback(void *arg);
%token K_BEGIN
%token K_CLOSE
%token K_CONSTANT
%token K_CONTINUE
%token K_CURSOR
%token K_DEBUG
%token K_DECLARE
......@@ -514,9 +516,9 @@ decl_renname : T_WORD
;
decl_const :
{ $$ = 0; }
{ $$ = false; }
| K_CONSTANT
{ $$ = 1; }
{ $$ = true; }
;
decl_datatype :
......@@ -531,9 +533,9 @@ decl_datatype :
;
decl_notnull :
{ $$ = 0; }
{ $$ = false; }
| K_NOT K_NULL
{ $$ = 1; }
{ $$ = true; }
;
decl_defval : ';'
......@@ -1035,13 +1037,14 @@ stmt_select : K_SELECT lno
}
;
stmt_exit : K_EXIT lno opt_exitlabel opt_exitcond
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->lineno = $2;
new->is_exit = $1;
new->lineno = $2;
new->label = $3;
new->cond = $4;
......@@ -1049,6 +1052,16 @@ stmt_exit : K_EXIT lno opt_exitlabel opt_exitcond
}
;
exit_type : K_EXIT
{
$$ = true;
}
| K_CONTINUE
{
$$ = false;
}
;
stmt_return : K_RETURN lno
{
PLpgSQL_stmt_return *new;
......@@ -1056,8 +1069,8 @@ stmt_return : K_RETURN lno
new = palloc0(sizeof(PLpgSQL_stmt_return));
new->cmd_type = PLPGSQL_STMT_RETURN;
new->lineno = $2;
new->expr = NULL;
new->retvarno = -1;
new->expr = NULL;
new->retvarno = -1;
if (plpgsql_curr_compile->fn_retset)
{
......
......@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.146 2005/06/20 22:51:29 tgl Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.147 2005/06/22 01:35:02 neilc Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
......@@ -194,6 +194,7 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo)
PLpgSQL_execstate estate;
ErrorContextCallback plerrcontext;
int i;
int rc;
/*
* Setup the execution state
......@@ -282,13 +283,24 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo)
*/
estate.err_text = NULL;
estate.err_stmt = (PLpgSQL_stmt *) (func->action);
if (exec_stmt_block(&estate, func->action) != PLPGSQL_RC_RETURN)
rc = exec_stmt_block(&estate, func->action);
if (rc != PLPGSQL_RC_RETURN)
{
estate.err_stmt = NULL;
estate.err_text = NULL;
ereport(ERROR,
(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
errmsg("control reached end of function without RETURN")));
/*
* Provide a more helpful message if a CONTINUE has been used
* outside a loop.
*/
if (rc == PLPGSQL_RC_CONTINUE)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("CONTINUE cannot be used outside a loop")));
else
ereport(ERROR,
(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
errmsg("control reached end of function without RETURN")));
}
/*
......@@ -393,6 +405,7 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
PLpgSQL_execstate estate;
ErrorContextCallback plerrcontext;
int i;
int rc;
PLpgSQL_var *var;
PLpgSQL_rec *rec_new,
*rec_old;
......@@ -546,13 +559,24 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
*/
estate.err_text = NULL;
estate.err_stmt = (PLpgSQL_stmt *) (func->action);
if (exec_stmt_block(&estate, func->action) != PLPGSQL_RC_RETURN)
rc = exec_stmt_block(&estate, func->action);
if (rc != PLPGSQL_RC_RETURN)
{
estate.err_stmt = NULL;
estate.err_text = NULL;
ereport(ERROR,
(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
errmsg("control reached end of trigger procedure without RETURN")));
/*
* Provide a more helpful message if a CONTINUE has been used
* outside a loop.
*/
if (rc == PLPGSQL_RC_CONTINUE)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("CONTINUE cannot be used outside a loop")));
else
ereport(ERROR,
(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
errmsg("control reached end of trigger procedure without RETURN")));
}
if (estate.retisset)
......@@ -919,7 +943,9 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
switch (rc)
{
case PLPGSQL_RC_OK:
return PLPGSQL_RC_OK;
case PLPGSQL_RC_CONTINUE:
case PLPGSQL_RC_RETURN:
return rc;
case PLPGSQL_RC_EXIT:
if (estate->exitlabel == NULL)
......@@ -930,10 +956,7 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
return PLPGSQL_RC_EXIT;
estate->exitlabel = NULL;
return PLPGSQL_RC_OK;
case PLPGSQL_RC_RETURN:
return PLPGSQL_RC_RETURN;
default:
elog(ERROR, "unrecognized rc: %d", rc);
}
......@@ -1120,7 +1143,7 @@ exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
{
PLpgSQL_diag_item *diag_item = (PLpgSQL_diag_item *) lfirst(lc);
PLpgSQL_datum *var;
bool isnull = false;
bool isnull;
if (diag_item->target <= 0)
continue;
......@@ -1165,7 +1188,7 @@ static int
exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
{
bool value;
bool isnull = false;
bool isnull;
value = exec_eval_boolean(estate, stmt->cond, &isnull);
exec_eval_cleanup(estate);
......@@ -1209,10 +1232,23 @@ exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
return PLPGSQL_RC_OK;
if (stmt->label == NULL)
return PLPGSQL_RC_EXIT;
if (strcmp(stmt->label, estate->exitlabel))
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 PLPGSQL_RC_RETURN;
......@@ -1236,7 +1272,7 @@ static int
exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
{
bool value;
bool isnull = false;
bool isnull;
int rc;
for (;;)
......@@ -1264,6 +1300,19 @@ exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
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 PLPGSQL_RC_RETURN;
......@@ -1288,7 +1337,7 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
PLpgSQL_var *var;
Datum value;
Oid valtype;
bool isnull = false;
bool isnull;
bool found = false;
int rc = PLPGSQL_RC_OK;
......@@ -1366,13 +1415,35 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
}
/*
* 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.
* 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)
/* anonymous continue, so 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, this is 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.
*/
break;
}
}
/*
* Increase/decrease loop var
......@@ -1459,17 +1530,8 @@ exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
* Execute the statements
*/
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)
......@@ -1490,6 +1552,34 @@ exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
* 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;
}
/*
* otherwise, we processed 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, 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;
}
......@@ -1563,7 +1653,7 @@ exec_stmt_select(PLpgSQL_execstate *estate, PLpgSQL_stmt_select *stmt)
n = estate->eval_processed;
/*
* If the query didn't return any row, set the target to NULL and
* If the query didn't return any rows, set the target to NULL and
* return.
*/
if (n == 0)
......@@ -1586,28 +1676,33 @@ exec_stmt_select(PLpgSQL_execstate *estate, PLpgSQL_stmt_select *stmt)
/* ----------
* exec_stmt_exit Start exiting loop(s) or blocks
* exec_stmt_exit Implements EXIT and CONTINUE
*
* This begins the process of exiting / restarting a loop.
* ----------
*/
static int
exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
{
/*
* If the exit has a condition, check that it's true
* If the exit / continue has a condition, evaluate it
*/
if (stmt->cond != NULL)
{
bool value;
bool isnull = false;
bool isnull;
value = exec_eval_boolean(estate, stmt->cond, &isnull);
exec_eval_cleanup(estate);
if (isnull || !value)
if (isnull || value == false)
return PLPGSQL_RC_OK;
}
estate->exitlabel = stmt->label;
return PLPGSQL_RC_EXIT;
if (stmt->is_exit)
return PLPGSQL_RC_EXIT;
else
return PLPGSQL_RC_CONTINUE;
}
......@@ -2455,14 +2550,6 @@ exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
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)
......@@ -2483,6 +2570,33 @@ exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
* 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;
}
/*
* otherwise, we process a labelled continue that
* does not match the current statement's label,
* so propagate RC_CONTINUE upward in the stack.
*/
}
/*
* 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;
}
......
......@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.44 2005/06/19 01:06:12 momjian Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.45 2005/06/22 01:35:02 neilc Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
......@@ -845,7 +845,8 @@ static void
dump_exit(PLpgSQL_stmt_exit *stmt)
{
dump_ind();
printf("EXIT lbl='%s'", stmt->label);
printf("%s label='%s'",
stmt->is_exit ? "EXIT" : "CONTINUE", stmt->label);
if (stmt->cond != NULL)
{
printf(" WHEN ");
......
......@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.63 2005/06/14 06:43:14 neilc Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.64 2005/06/22 01:35:02 neilc Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
......@@ -125,7 +125,8 @@ enum
{
PLPGSQL_RC_OK,
PLPGSQL_RC_EXIT,
PLPGSQL_RC_RETURN
PLPGSQL_RC_RETURN,
PLPGSQL_RC_CONTINUE
};
/* ----------
......@@ -485,9 +486,10 @@ typedef struct
typedef struct
{ /* EXIT statement */
{ /* EXIT or CONTINUE statement */
int cmd_type;
int lineno;
bool is_exit; /* Is this an exit or a continue? */
char *label;
PLpgSQL_expr *cond;
} PLpgSQL_stmt_exit;
......@@ -610,7 +612,8 @@ typedef struct
bool readonly_func;
TupleDesc rettupdesc;
char *exitlabel;
char *exitlabel; /* the "target" label of the current
* EXIT or CONTINUE stmt, if any */
Tuplestorestate *tuple_store; /* SRFs accumulate results here */
MemoryContext tuple_store_cxt;
......
......@@ -4,7 +4,7 @@
* procedural language
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.40 2005/03/11 19:13:43 momjian Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.41 2005/06/22 01:35:02 neilc Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
......@@ -139,6 +139,7 @@ alias { return K_ALIAS; }
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; }
......
......@@ -2491,3 +2491,140 @@ NOTICE: {10,20,30}; 20; xyz; xyzabc; (10,aaa,,30); <NULL>
(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"
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 function continue_test1() 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---';
<<the_loop>>
while _i < 10 loop
_i := _i + 1;
continue the_loop when _i % 2 = 0;
raise notice '%', _i;
end loop;
raise notice '---4---';
for _i in 1..10 loop
begin
-- applies to outer loop, not the nested begin block
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 continue_test1();
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
continue_test1
----------------
(1 row)
-- CONTINUE is only legal inside a loop
create function continue_test2() returns void as $$
begin
begin
continue;
end;
return;
end;
$$ language plpgsql;
-- should fail
select continue_test2();
ERROR: CONTINUE cannot be used outside a loop
CONTEXT: PL/pgSQL function "continue_test2"
-- CONTINUE can't reference the label of a named block
create function continue_test3() returns void as $$
begin
<<begin_block1>>
begin
loop
continue begin_block1;
end loop;
end;
end;
$$ language plpgsql;
-- should fail
select continue_test3();
ERROR: CONTINUE cannot be used outside a loop
CONTEXT: PL/pgSQL function "continue_test3"
drop function continue_test1();
drop function continue_test2();
drop function continue_test3();
drop table conttesttbl;
......@@ -2112,3 +2112,97 @@ end;$$ language plpgsql;
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 function continue_test1() 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---';
<<the_loop>>
while _i < 10 loop
_i := _i + 1;
continue the_loop when _i % 2 = 0;
raise notice '%', _i;
end loop;
raise notice '---4---';
for _i in 1..10 loop
begin
-- applies to outer loop, not the nested begin block
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 continue_test1();
-- CONTINUE is only legal inside a loop
create function continue_test2() returns void as $$
begin
begin
continue;
end;
return;
end;
$$ language plpgsql;
-- should fail
select continue_test2();
-- CONTINUE can't reference the label of a named block
create function continue_test3() returns void as $$
begin
<<begin_block1>>
begin
loop
continue begin_block1;
end loop;
end;
end;
$$ language plpgsql;
-- should fail
select continue_test3();
drop function continue_test1();
drop function continue_test2();
drop function continue_test3();
drop table conttesttbl;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册