Fix plpgsql's EXIT so that an EXIT without a label only matches a loop,
authorTom Lane
Sat, 2 May 2009 17:27:57 +0000 (17:27 +0000)
committerTom Lane
Sat, 2 May 2009 17:27:57 +0000 (17:27 +0000)
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.

doc/src/sgml/plpgsql.sgml
src/pl/plpgsql/src/pl_exec.c

index 319547ec0016eee60aa0c8140fbea55b51597f3b..3788b8004b09b35eb557d09cc5aedb6982d146e6 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
 
   <application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language
@@ -1904,8 +1904,8 @@ END LOOP  label ;
       indefinitely until terminated by an EXIT or
       RETURN statement.  The optional
       label can be used by EXIT
-      and CONTINUE statements in nested loops to
-      specify which loop the statement should be applied to.
+      and CONTINUE statements within nested loops to
+      specify which loop those statements refer to.
      
     
 
@@ -1939,9 +1939,19 @@ EXIT  label   WHEN 
 
        
         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.
+       
+
+       
+        When used with a
         BEGIN block, EXIT passes
         control to the next statement after the end of the block.
+        Note that a label must be used for this purpose; an unlabelled
+        EXIT is never considered to match a
+        BEGIN block.  (This is a change from
+        pre-8.4 releases of PostgreSQL, which
+        would allow an unlabelled EXIT to match
+        a BEGIN block.)
        
 
        
@@ -1959,11 +1969,13 @@ LOOP
     EXIT WHEN count > 0;  -- same result as previous example
 END LOOP;
 
+<<ablock>>
 BEGIN
     -- some computations
     IF stocks > 100000 THEN
-        EXIT;  -- causes exit from the BEGIN block
+        EXIT ablock;  -- causes exit from the BEGIN block
     END IF;
+    -- computations here will be skipped when stocks > 100000
 END;
 
        
index d440d38e56799de0873ca0759357bda07c8d9507..e436e053b1b75d4950b3d6d67ca814436a377734 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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)
            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_OK;
+               return PLPGSQL_RC_EXIT;
            if (block->label == NULL)
                return PLPGSQL_RC_EXIT;
-           if (strcmp(block->label, estate->exitlabel))
+           if (strcmp(block->label, estate->exitlabel) != 0)
                return PLPGSQL_RC_EXIT;
            estate->exitlabel = NULL;
            return PLPGSQL_RC_OK;
@@ -1604,7 +1608,7 @@ exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *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;