Pavel Stehule wrote:
this patch allows optional using label with END and END LOOP. Ending label has only informational value, but can enhance readability large block and enhance likeness with Oracle.


<<main>>LOOP
 ...
 ...
END LOOP<<main>>;

Attached is a revised version of this patch. Changes / comments:

- AFAICS Oracle's syntax is actually

<<label>> LOOP
...
END LOOP label;

i.e. the ending block label isn't enclosed in <<>>. I've adjusted the patch accordingly.

- your patch broke EXIT and CONTINUE, as running the regression tests would have made clear.

- yyerror() will set plpgsql_error_lineno, so you needn't do it yourself. I changed it to use ereport(ERROR) anyway, as it seems a bit more appropriate. I'm not quite happy with the error message text:

ERROR:  end label "outer_label" differs from block's label "inner_label"
CONTEXT:  compile of PL/pgSQL function "end_label3" near line 6

ERROR:  end label "outer_label" specified for unlabelled block
CONTEXT:  compile of PL/pgSQL function "end_label4" near line 5

suggestions for improvement are welcome.

BTW, I notice that some but not all the call sites of ereport(ERROR) in PL/PgSQL's gram.y set plpgsql_error_lineno. Is there a reason for this?

Barring any objections, I'll apply the attached patch to CVS tomorrow.

-Neil
Index: doc/src/sgml/plpgsql.sgml
===================================================================
RCS file: /Users/neilc/local/cvs/pgsql/doc/src/sgml/plpgsql.sgml,v
retrieving revision 1.74
diff -c -r1.74 plpgsql.sgml
*** doc/src/sgml/plpgsql.sgml   22 Jun 2005 01:35:02 -0000      1.74
--- doc/src/sgml/plpgsql.sgml   1 Jul 2005 11:43:36 -0000
***************
*** 456,462 ****
      <replaceable>declarations</replaceable> </optional>
  BEGIN
      <replaceable>statements</replaceable>
! END;
  </synopsis>
      </para>
  
--- 456,462 ----
      <replaceable>declarations</replaceable> </optional>
  BEGIN
      <replaceable>statements</replaceable>
! END <optional> <replaceable>label</replaceable> </optional>;
  </synopsis>
      </para>
  
***************
*** 1789,1806 ****
       <title><literal>LOOP</></title>
  
  <synopsis>
! <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  LOOP
      <replaceable>statements</replaceable>
! END LOOP;
  </synopsis>
  
       <para>
!       <literal>LOOP</> defines an unconditional loop that is repeated 
indefinitely
!       until terminated by an <literal>EXIT</> or <command>RETURN</command>
!       statement.  The optional label can be used by <literal>EXIT</> 
statements in
!       nested loops to specify which level of nesting should be
!       terminated.
       </para>
      </sect3>
  
--- 1789,1807 ----
       <title><literal>LOOP</></title>
  
  <synopsis>
! <optional> &lt;&lt;<replaceable>label</replaceable>&gt;&gt; </optional>
  LOOP
      <replaceable>statements</replaceable>
! END LOOP <optional> <replaceable>label</replaceable> </optional>;
  </synopsis>
  
       <para>
!       <literal>LOOP</> defines an unconditional loop that is repeated
!       indefinitely until terminated by an <literal>EXIT</> or
!       <command>RETURN</command> statement.  The optional
!       <replaceable>label</replaceable> can be used by <literal>EXIT</>
!       and <literal>CONTINUE</literal> statements in nested loops to
!       specify which loop the statement should be applied to.
       </para>
      </sect3>
  
***************
*** 1920,1929 ****
       </indexterm>
  
  <synopsis>
! <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  WHILE <replaceable>expression</replaceable> LOOP
      <replaceable>statements</replaceable>
! END LOOP;
  </synopsis>
  
         <para>
--- 1921,1930 ----
       </indexterm>
  
  <synopsis>
! <optional> &lt;&lt;<replaceable>label</replaceable>&gt;&gt; </optional>
  WHILE <replaceable>expression</replaceable> LOOP
      <replaceable>statements</replaceable>
! END LOOP <optional> <replaceable>label</replaceable> </optional>;
  </synopsis>
  
         <para>
***************
*** 1951,1960 ****
        <title><literal>FOR</> (integer variant)</title>
  
  <synopsis>
! <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  FOR <replaceable>name</replaceable> IN <optional> REVERSE </optional> 
<replaceable>expression</replaceable> .. <replaceable>expression</replaceable> 
LOOP
      <replaceable>statements</replaceable>
! END LOOP;
  </synopsis>
  
         <para>
--- 1952,1961 ----
        <title><literal>FOR</> (integer variant)</title>
  
  <synopsis>
! <optional> &lt;&lt;<replaceable>label</replaceable>&gt;&gt; </optional>
  FOR <replaceable>name</replaceable> IN <optional> REVERSE </optional> 
<replaceable>expression</replaceable> .. <replaceable>expression</replaceable> 
LOOP
      <replaceable>statements</replaceable>
! END LOOP <optional> <replaceable>labal</replaceable> </optional>;
  </synopsis>
  
         <para>
***************
*** 1997,2006 ****
       the results of a query and manipulate that data
       accordingly. The syntax is:
  <synopsis>
! <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  FOR <replaceable>record_or_row</replaceable> IN 
<replaceable>query</replaceable> LOOP
      <replaceable>statements</replaceable>
! END LOOP;
  </synopsis>
       The record or row variable is successively assigned each row
       resulting from the <replaceable>query</replaceable> (which must be a
--- 1998,2007 ----
       the results of a query and manipulate that data
       accordingly. The syntax is:
  <synopsis>
! <optional> &lt;&lt;<replaceable>label</replaceable>&gt;&gt; </optional>
  FOR <replaceable>record_or_row</replaceable> IN 
<replaceable>query</replaceable> LOOP
      <replaceable>statements</replaceable>
! END LOOP <optional> <replaceable>label</replaceable> </optional>;
  </synopsis>
       The record or row variable is successively assigned each row
       resulting from the <replaceable>query</replaceable> (which must be a
***************
*** 2036,2045 ****
       The <literal>FOR-IN-EXECUTE</> statement is another way to iterate over
       rows:
  <synopsis>
! <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  FOR <replaceable>record_or_row</replaceable> IN EXECUTE 
<replaceable>text_expression</replaceable> LOOP 
      <replaceable>statements</replaceable>
! END LOOP;
  </synopsis>
       This is like the previous form, except that the source
       <command>SELECT</command> statement is specified as a string
--- 2037,2046 ----
       The <literal>FOR-IN-EXECUTE</> statement is another way to iterate over
       rows:
  <synopsis>
! <optional> &lt;&lt;<replaceable>label</replaceable>&gt;&gt; </optional>
  FOR <replaceable>record_or_row</replaceable> IN EXECUTE 
<replaceable>text_expression</replaceable> LOOP 
      <replaceable>statements</replaceable>
! END LOOP <optional> <replaceable>label</replaceable> </optional>;
  </synopsis>
       This is like the previous form, except that the source
       <command>SELECT</command> statement is specified as a string
Index: src/pl/plpgsql/src/gram.y
===================================================================
RCS file: /Users/neilc/local/cvs/pgsql/src/pl/plpgsql/src/gram.y,v
retrieving revision 1.77
diff -c -r1.77 gram.y
*** src/pl/plpgsql/src/gram.y   22 Jun 2005 01:35:02 -0000      1.77
--- src/pl/plpgsql/src/gram.y   1 Jul 2005 12:08:45 -0000
***************
*** 56,61 ****
--- 56,63 ----
                                                                                
           PLpgSQL_datum *initial_datum);
  static        void                     check_sql_expr(const char *stmt);
  static        void                     plpgsql_sql_error_callback(void *arg);
+ static        void                     check_labels(const char *start_label,
+                                                                         const 
char *end_label);
  
  %}
  
***************
*** 69,75 ****
                        int  lineno;
                }                                               varname;
                struct
!               {    
                        char *name;
                        int  lineno;
                        PLpgSQL_rec     *rec;
--- 71,77 ----
                        int  lineno;
                }                                               varname;
                struct
!               {
                        char *name;
                        int  lineno;
                        PLpgSQL_rec     *rec;
***************
*** 81,86 ****
--- 83,93 ----
                        int  n_initvars;
                        int  *initvarnos;
                }                                               declhdr;
+               struct
+               {
+                       char *end_label;
+                       List *stmts;
+               }                                               loop_body;
                List                                    *list;
                PLpgSQL_type                    *dtype;
                PLpgSQL_datum                   *scalar;        /* a VAR, 
RECFIELD, or TRIGARG */
***************
*** 119,129 ****
  %type <forvariable>   for_variable
  %type <stmt>  for_control
  
! %type <str>           opt_lblname opt_label
! %type <str>           opt_exitlabel
  %type <str>           execsql_start
  
! %type <list>  proc_sect proc_stmts stmt_else loop_body
  %type <stmt>  proc_stmt pl_block
  %type <stmt>  stmt_assign stmt_if stmt_loop stmt_while stmt_exit
  %type <stmt>  stmt_return stmt_return_next stmt_raise stmt_execsql
--- 126,136 ----
  %type <forvariable>   for_variable
  %type <stmt>  for_control
  
! %type <str>           opt_lblname opt_block_label opt_label
  %type <str>           execsql_start
  
! %type <list>  proc_sect proc_stmts stmt_else
! %type <loop_body>     loop_body
  %type <stmt>  proc_stmt pl_block
  %type <stmt>  stmt_assign stmt_if stmt_loop stmt_while stmt_exit
  %type <stmt>  stmt_return stmt_return_next stmt_raise stmt_execsql
***************
*** 248,257 ****
                                | ';'
                                ;
  
! pl_block              : decl_sect K_BEGIN lno proc_sect exception_sect K_END
                                        {
                                                PLpgSQL_stmt_block *new;
  
                                                new = 
palloc0(sizeof(PLpgSQL_stmt_block));
  
                                                new->cmd_type   = 
PLPGSQL_STMT_BLOCK;
--- 255,266 ----
                                | ';'
                                ;
  
! pl_block              : decl_sect K_BEGIN lno proc_sect exception_sect K_END 
opt_label
                                        {
                                                PLpgSQL_stmt_block *new;
  
+                                               check_labels($1.label, $7);
+ 
                                                new = 
palloc0(sizeof(PLpgSQL_stmt_block));
  
                                                new->cmd_type   = 
PLPGSQL_STMT_BLOCK;
***************
*** 269,275 ****
                                ;
  
  
! decl_sect             : opt_label
                                        {
                                                plpgsql_ns_setlocal(false);
                                                $$.label          = $1;
--- 278,284 ----
                                ;
  
  
! decl_sect             : opt_block_label
                                        {
                                                plpgsql_ns_setlocal(false);
                                                $$.label          = $1;
***************
*** 277,283 ****
                                                $$.initvarnos = NULL;
                                                plpgsql_add_initdatums(NULL);
                                        }
!                               | opt_label decl_start
                                        {
                                                plpgsql_ns_setlocal(false);
                                                $$.label          = $1;
--- 286,292 ----
                                                $$.initvarnos = NULL;
                                                plpgsql_add_initdatums(NULL);
                                        }
!                               | opt_block_label decl_start
                                        {
                                                plpgsql_ns_setlocal(false);
                                                $$.label          = $1;
***************
*** 285,291 ****
                                                $$.initvarnos = NULL;
                                                plpgsql_add_initdatums(NULL);
                                        }
!                               | opt_label decl_start decl_stmts
                                        {
                                                plpgsql_ns_setlocal(false);
                                                if ($3 != NULL)
--- 294,300 ----
                                                $$.initvarnos = NULL;
                                                plpgsql_add_initdatums(NULL);
                                        }
!                               | opt_block_label decl_start decl_stmts
                                        {
                                                plpgsql_ns_setlocal(false);
                                                if ($3 != NULL)
***************
*** 409,415 ****
                                                plpgsql_ns_setlocal(false);
                                                query = read_sql_stmt("");
                                                plpgsql_ns_setlocal(true);
!                                               
                                                $$ = query;
                                        }
                                ;
--- 418,424 ----
                                                plpgsql_ns_setlocal(false);
                                                query = read_sql_stmt("");
                                                plpgsql_ns_setlocal(true);
! 
                                                $$ = query;
                                        }
                                ;
***************
*** 757,763 ****
                                                 *       ...                    
                                   ...
                                                 * ELSE                         
                           ELSE
                                                 *       ...                    
                                   ...
!                                                * END IF                       
                           END IF                        
                                                 *                              
                           END IF
                                                 */
                                                PLpgSQL_stmt_if *new_if;
--- 766,772 ----
                                                 *       ...                    
                                   ...
                                                 * ELSE                         
                           ELSE
                                                 *       ...                    
                                   ...
!                                                * END IF                       
                           END IF
                                                 *                              
                           END IF
                                                 */
                                                PLpgSQL_stmt_if *new_if;
***************
*** 776,786 ****
  
                                | K_ELSE proc_sect
                                        {
!                                               $$ = $2;                        
        
                                        }
                                ;
  
! stmt_loop             : opt_label K_LOOP lno loop_body
                                        {
                                                PLpgSQL_stmt_loop *new;
  
--- 785,795 ----
  
                                | K_ELSE proc_sect
                                        {
!                                               $$ = $2;
                                        }
                                ;
  
! stmt_loop             : opt_block_label K_LOOP lno loop_body
                                        {
                                                PLpgSQL_stmt_loop *new;
  
***************
*** 788,802 ****
                                                new->cmd_type = 
PLPGSQL_STMT_LOOP;
                                                new->lineno   = $3;
                                                new->label        = $1;
!                                               new->body         = $4;
  
                                                plpgsql_ns_pop();
  
                                                $$ = (PLpgSQL_stmt *)new;
                                        }
                                ;
  
! stmt_while            : opt_label K_WHILE lno expr_until_loop loop_body
                                        {
                                                PLpgSQL_stmt_while *new;
  
--- 797,812 ----
                                                new->cmd_type = 
PLPGSQL_STMT_LOOP;
                                                new->lineno   = $3;
                                                new->label        = $1;
!                                               new->body         = $4.stmts;
  
+                                               check_labels($1, $4.end_label);
                                                plpgsql_ns_pop();
  
                                                $$ = (PLpgSQL_stmt *)new;
                                        }
                                ;
  
! stmt_while            : opt_block_label K_WHILE lno expr_until_loop loop_body
                                        {
                                                PLpgSQL_stmt_while *new;
  
***************
*** 805,819 ****
                                                new->lineno   = $3;
                                                new->label        = $1;
                                                new->cond         = $4;
!                                               new->body         = $5;
  
                                                plpgsql_ns_pop();
  
                                                $$ = (PLpgSQL_stmt *)new;
                                        }
                                ;
  
! stmt_for              : opt_label K_FOR for_control loop_body
                                        {
                                                /* This runs after we've 
scanned the loop body */
                                                if ($3->cmd_type == 
PLPGSQL_STMT_FORI)
--- 815,830 ----
                                                new->lineno   = $3;
                                                new->label        = $1;
                                                new->cond         = $4;
!                                               new->body         = $5.stmts;
  
+                                               check_labels($1, $5.end_label);
                                                plpgsql_ns_pop();
  
                                                $$ = (PLpgSQL_stmt *)new;
                                        }
                                ;
  
! stmt_for              : opt_block_label K_FOR for_control loop_body
                                        {
                                                /* This runs after we've 
scanned the loop body */
                                                if ($3->cmd_type == 
PLPGSQL_STMT_FORI)
***************
*** 822,828 ****
  
                                                        new = 
(PLpgSQL_stmt_fori *) $3;
                                                        new->label        = $1;
!                                                       new->body         = $4;
                                                        $$ = (PLpgSQL_stmt *) 
new;
                                                }
                                                else if ($3->cmd_type == 
PLPGSQL_STMT_FORS)
--- 833,839 ----
  
                                                        new = 
(PLpgSQL_stmt_fori *) $3;
                                                        new->label        = $1;
!                                                       new->body         = 
$4.stmts;
                                                        $$ = (PLpgSQL_stmt *) 
new;
                                                }
                                                else if ($3->cmd_type == 
PLPGSQL_STMT_FORS)
***************
*** 831,837 ****
  
                                                        new = 
(PLpgSQL_stmt_fors *) $3;
                                                        new->label        = $1;
!                                                       new->body         = $4;
                                                        $$ = (PLpgSQL_stmt *) 
new;
                                                }
                                                else
--- 842,848 ----
  
                                                        new = 
(PLpgSQL_stmt_fors *) $3;
                                                        new->label        = $1;
!                                                       new->body         = 
$4.stmts;
                                                        $$ = (PLpgSQL_stmt *) 
new;
                                                }
                                                else
***************
*** 841,850 ****
                                                        Assert($3->cmd_type == 
PLPGSQL_STMT_DYNFORS);
                                                        new = 
(PLpgSQL_stmt_dynfors *) $3;
                                                        new->label        = $1;
!                                                       new->body         = $4;
                                                        $$ = (PLpgSQL_stmt *) 
new;
                                                }
  
                                                /* close namespace started in 
opt_label */
                                                plpgsql_ns_pop();
                                        }
--- 852,862 ----
                                                        Assert($3->cmd_type == 
PLPGSQL_STMT_DYNFORS);
                                                        new = 
(PLpgSQL_stmt_dynfors *) $3;
                                                        new->label        = $1;
!                                                       new->body         = 
$4.stmts;
                                                        $$ = (PLpgSQL_stmt *) 
new;
                                                }
  
+                                               check_labels($1, $4.end_label);
                                                /* close namespace started in 
opt_label */
                                                plpgsql_ns_pop();
                                        }
***************
*** 1037,1043 ****
                                        }
                                ;
  
! stmt_exit             : exit_type lno opt_exitlabel opt_exitcond
                                        {
                                                PLpgSQL_stmt_exit *new;
  
--- 1049,1055 ----
                                        }
                                ;
  
! stmt_exit             : exit_type lno opt_label opt_exitcond
                                        {
                                                PLpgSQL_stmt_exit *new;
  
***************
*** 1245,1252 ****
                                        }
                                ;
  
! loop_body             : proc_sect K_END K_LOOP ';'
!                                       { $$ = $1; }
                                ;
  
  stmt_execsql  : execsql_start lno
--- 1257,1267 ----
                                        }
                                ;
  
! loop_body             : proc_sect K_END K_LOOP opt_label ';'
!                                       {
!                                               $$.stmts = $1;
!                                               $$.end_label = $4;
!                                       }
                                ;
  
  stmt_execsql  : execsql_start lno
***************
*** 1262,1268 ****
                                        }
                                ;
  
! stmt_dynexecute : K_EXECUTE lno 
                                        {
                                                PLpgSQL_stmt_dynexecute *new;
                                                PLpgSQL_expr *expr;
--- 1277,1283 ----
                                        }
                                ;
  
! stmt_dynexecute : K_EXECUTE lno
                                        {
                                                PLpgSQL_stmt_dynexecute *new;
                                                PLpgSQL_expr *expr;
***************
*** 1418,1424 ****
                                                                                
         errmsg("cursor \"%s\" has no arguments",
                                                                                
                        $3->refname)));
                                                                }
!                                                               
                                                                if (tok != ';')
                                                                {
                                                                        
plpgsql_error_lineno = plpgsql_scanner_lineno();
--- 1433,1439 ----
                                                                                
         errmsg("cursor \"%s\" has no arguments",
                                                                                
                        $3->refname)));
                                                                }
! 
                                                                if (tok != ';')
                                                                {
                                                                        
plpgsql_error_lineno = plpgsql_scanner_lineno();
***************
*** 1596,1602 ****
                                        { $$ = plpgsql_read_expression(K_LOOP, 
"LOOP"); }
                                ;
  
! opt_label             :
                                        {
                                                plpgsql_ns_push(NULL);
                                                $$ = NULL;
--- 1611,1617 ----
                                        { $$ = plpgsql_read_expression(K_LOOP, 
"LOOP"); }
                                ;
  
! opt_block_label       :
                                        {
                                                plpgsql_ns_push(NULL);
                                                $$ = NULL;
***************
*** 1608,1621 ****
                                        }
                                ;
  
! opt_exitlabel :
!                                       { $$ = NULL; }
                                | T_LABEL
                                        {
!                                               char    *name;
! 
!                                               plpgsql_convert_ident(yytext, 
&name, 1);
!                                               $$ = name;
                                        }
                                | T_WORD
                                        {
--- 1623,1637 ----
                                        }
                                ;
  
! opt_label     :
!                                       {
!                                               $$ = NULL;
!                                       }
                                | T_LABEL
                                        {
!                                               char *label_name;
!                                               plpgsql_convert_ident(yytext, 
&label_name, 1);
!                                               $$ = label_name;
                                        }
                                | T_WORD
                                        {
***************
*** 2210,2213 ****
--- 2226,2254 ----
        errposition(0);
  }
  
+ static void
+ check_labels(const char *start_label, const char *end_label)
+ {
+       if (end_label)
+       {
+               if (!start_label)
+               {
+                       plpgsql_error_lineno = plpgsql_scanner_lineno();
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_SYNTAX_ERROR),
+                                        errmsg("end label \"%s\" specified for 
unlabelled block",
+                                                       end_label)));
+               }
+ 
+               if (strcmp(start_label, end_label) != 0)
+               {
+                       plpgsql_error_lineno = plpgsql_scanner_lineno();
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_SYNTAX_ERROR),
+                                        errmsg("end label \"%s\" differs from 
block's label \"%s\"",
+                                                       end_label, 
start_label)));
+               }
+       }
+ }
+ 
  #include "pl_scan.c"
Index: src/test/regress/expected/plpgsql.out
===================================================================
RCS file: /Users/neilc/local/cvs/pgsql/src/test/regress/expected/plpgsql.out,v
retrieving revision 1.36
diff -c -r1.36 plpgsql.out
*** src/test/regress/expected/plpgsql.out       22 Jun 2005 07:28:47 -0000      
1.36
--- src/test/regress/expected/plpgsql.out       1 Jul 2005 11:53:55 -0000
***************
*** 2491,2497 ****
  (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);
--- 2491,2497 ----
  (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);
***************
*** 2532,2538 ****
    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;
--- 2532,2538 ----
    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;
***************
*** 2666,2668 ****
--- 2666,2723 ----
  drop function continue_test2();
  drop function continue_test3();
  drop table conttesttbl;
+ -- verbose end block and end loop
+ create function end_label1() returns void as $$
+ <<blbl>>
+ begin
+   <<flbl1>>
+   for _i in 1 .. 10 loop
+     exit flbl1;
+   end loop flbl1;
+   <<flbl2>>
+   for _i in 1 .. 10 loop
+     exit flbl2;
+   end loop;
+ end blbl;
+ $$ language plpgsql;
+ select end_label1();
+  end_label1 
+ ------------
+  
+ (1 row)
+ 
+ drop function end_label1();
+ -- should fail: undefined end label
+ create function end_label2() returns void as $$
+ begin
+   for _i in 1 .. 10 loop
+     exit;
+   end loop flbl1;
+ end;
+ $$ language plpgsql;
+ ERROR:  no such label at or near "flbl1" at character 101
+ LINE 5:   end loop flbl1;
+                    ^
+ -- should fail: end label does not match start label
+ create function end_label3() returns void as $$
+ <<outer_label>>
+ begin
+   <<inner_label>>
+   for _i in 1 .. 10 loop
+     exit;
+   end loop outer_label;
+ end;
+ $$ language plpgsql;
+ ERROR:  end label "outer_label" differs from block's label "inner_label"
+ CONTEXT:  compile of PL/pgSQL function "end_label3" near line 6
+ -- should fail: end label on a block without a start label
+ create function end_label4() returns void as $$
+ <<outer_label>>
+ begin
+   for _i in 1 .. 10 loop
+     exit;
+   end loop outer_label;
+ end;
+ $$ language plpgsql;
+ ERROR:  end label "outer_label" specified for unlabelled block
+ CONTEXT:  compile of PL/pgSQL function "end_label4" near line 5
Index: src/test/regress/sql/plpgsql.sql
===================================================================
RCS file: /Users/neilc/local/cvs/pgsql/src/test/regress/sql/plpgsql.sql,v
retrieving revision 1.31
diff -c -r1.31 plpgsql.sql
*** src/test/regress/sql/plpgsql.sql    22 Jun 2005 07:28:47 -0000      1.31
--- src/test/regress/sql/plpgsql.sql    1 Jul 2005 11:43:36 -0000
***************
*** 2113,2119 ****
  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);
--- 2113,2119 ----
  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);
***************
*** 2154,2160 ****
    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;
--- 2154,2160 ----
    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;
***************
*** 2232,2234 ****
--- 2232,2282 ----
  drop function continue_test2();
  drop function continue_test3();
  drop table conttesttbl;
+ 
+ -- verbose end block and end loop
+ create function end_label1() returns void as $$
+ <<blbl>>
+ begin
+   <<flbl1>>
+   for _i in 1 .. 10 loop
+     exit flbl1;
+   end loop flbl1;
+   <<flbl2>>
+   for _i in 1 .. 10 loop
+     exit flbl2;
+   end loop;
+ end blbl;
+ $$ language plpgsql;
+ 
+ select end_label1();
+ drop function end_label1();
+ 
+ -- should fail: undefined end label
+ create function end_label2() returns void as $$
+ begin
+   for _i in 1 .. 10 loop
+     exit;
+   end loop flbl1;
+ end;
+ $$ language plpgsql;
+ 
+ -- should fail: end label does not match start label
+ create function end_label3() returns void as $$
+ <<outer_label>>
+ begin
+   <<inner_label>>
+   for _i in 1 .. 10 loop
+     exit;
+   end loop outer_label;
+ end;
+ $$ language plpgsql;
+ 
+ -- should fail: end label on a block without a start label
+ create function end_label4() returns void as $$
+ <<outer_label>>
+ begin
+   for _i in 1 .. 10 loop
+     exit;
+   end loop outer_label;
+ end;
+ $$ language plpgsql;
---------------------------(end of broadcast)---------------------------
TIP 8: explain analyze is your friend

Reply via email to