Commit c91bf01b authored by Tom Lane's avatar Tom Lane

Fix plpgsql's EXIT so that an EXIT without a label only matches a loop,

never a BEGIN block.  This is required for Oracle compatibility and is
also plainly stated to be the behavior by our original documentation
(up until 8.1, in which the docs were adjusted to match the code's behavior;
but actually the old docs said the correct thing and the code was wrong).

Not back-patched because this introduces an incompatibility that could
break working applications.  Requires release note.
parent ccc6759d
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.140 2009/04/19 18:52:56 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.141 2009/05/02 17:27:57 tgl Exp $ -->
<chapter id="plpgsql"> <chapter id="plpgsql">
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title> <title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
...@@ -1904,8 +1904,8 @@ END LOOP <optional> <replaceable>label</replaceable> </optional>; ...@@ -1904,8 +1904,8 @@ END LOOP <optional> <replaceable>label</replaceable> </optional>;
indefinitely until terminated by an <literal>EXIT</> or indefinitely until terminated by an <literal>EXIT</> or
<command>RETURN</command> statement. The optional <command>RETURN</command> statement. The optional
<replaceable>label</replaceable> can be used by <literal>EXIT</> <replaceable>label</replaceable> can be used by <literal>EXIT</>
and <literal>CONTINUE</literal> statements in nested loops to and <literal>CONTINUE</literal> statements within nested loops to
specify which loop the statement should be applied to. specify which loop those statements refer to.
</para> </para>
</sect3> </sect3>
...@@ -1939,9 +1939,19 @@ EXIT <optional> <replaceable>label</replaceable> </optional> <optional> WHEN <re ...@@ -1939,9 +1939,19 @@ EXIT <optional> <replaceable>label</replaceable> </optional> <optional> WHEN <re
<para> <para>
<literal>EXIT</> can be used with all types of loops; it is <literal>EXIT</> can be used with all types of loops; it is
not limited to use with unconditional loops. When used with a not limited to use with unconditional loops.
</para>
<para>
When used with a
<literal>BEGIN</literal> block, <literal>EXIT</literal> passes <literal>BEGIN</literal> block, <literal>EXIT</literal> passes
control to the next statement after the end of the block. control to the next statement after the end of the block.
Note that a label must be used for this purpose; an unlabelled
<literal>EXIT</literal> is never considered to match a
<literal>BEGIN</literal> block. (This is a change from
pre-8.4 releases of <productname>PostgreSQL</productname>, which
would allow an unlabelled <literal>EXIT</literal> to match
a <literal>BEGIN</literal> block.)
</para> </para>
<para> <para>
...@@ -1959,11 +1969,13 @@ LOOP ...@@ -1959,11 +1969,13 @@ LOOP
EXIT WHEN count &gt; 0; -- same result as previous example EXIT WHEN count &gt; 0; -- same result as previous example
END LOOP; END LOOP;
&lt;&lt;ablock&gt;&gt;
BEGIN BEGIN
-- some computations -- some computations
IF stocks &gt; 100000 THEN IF stocks &gt; 100000 THEN
EXIT; -- causes exit from the BEGIN block EXIT ablock; -- causes exit from the BEGIN block
END IF; END IF;
-- computations here will be skipped when stocks &gt; 100000
END; END;
</programlisting> </programlisting>
</para> </para>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.240 2009/04/09 02:57:53 tgl Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.241 2009/05/02 17:27:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1145,11 +1145,15 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) ...@@ -1145,11 +1145,15 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
return rc; return rc;
case PLPGSQL_RC_EXIT: 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) if (estate->exitlabel == NULL)
return PLPGSQL_RC_OK; return PLPGSQL_RC_EXIT;
if (block->label == NULL) if (block->label == NULL)
return PLPGSQL_RC_EXIT; return PLPGSQL_RC_EXIT;
if (strcmp(block->label, estate->exitlabel)) if (strcmp(block->label, estate->exitlabel) != 0)
return PLPGSQL_RC_EXIT; return PLPGSQL_RC_EXIT;
estate->exitlabel = NULL; estate->exitlabel = NULL;
return PLPGSQL_RC_OK; return PLPGSQL_RC_OK;
...@@ -1604,7 +1608,7 @@ exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt) ...@@ -1604,7 +1608,7 @@ exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
return PLPGSQL_RC_OK; return PLPGSQL_RC_OK;
if (stmt->label == NULL) if (stmt->label == NULL)
return PLPGSQL_RC_EXIT; return PLPGSQL_RC_EXIT;
if (strcmp(stmt->label, estate->exitlabel)) if (strcmp(stmt->label, estate->exitlabel) != 0)
return PLPGSQL_RC_EXIT; return PLPGSQL_RC_EXIT;
estate->exitlabel = NULL; estate->exitlabel = NULL;
return PLPGSQL_RC_OK; return PLPGSQL_RC_OK;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment