Hello

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>>;

Regards
Pavel Stehule
diff -c -r --new-file pgsql/doc/src/sgml/plpgsql.sgml 
pgsql.01/doc/src/sgml/plpgsql.sgml
*** pgsql/doc/src/sgml/plpgsql.sgml     2005-06-24 13:10:33.000000000 +0200
--- pgsql.01/doc/src/sgml/plpgsql.sgml  2005-06-25 15:29:27.000000000 +0200
***************
*** 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> &lt;&lt;<replaceable>label</replaceable>&gt;&gt; </optional>;
  </synopsis>
      </para>
  
***************
*** 1792,1798 ****
  <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  LOOP
      <replaceable>statements</replaceable>
! END LOOP;
  </synopsis>
  
       <para>
--- 1792,1798 ----
  <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  LOOP
      <replaceable>statements</replaceable>
! END LOOP 
<optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>;
  </synopsis>
  
       <para>
***************
*** 1923,1929 ****
  <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  WHILE <replaceable>expression</replaceable> LOOP
      <replaceable>statements</replaceable>
! END LOOP;
  </synopsis>
  
         <para>
--- 1923,1929 ----
  <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  WHILE <replaceable>expression</replaceable> LOOP
      <replaceable>statements</replaceable>
! END LOOP 
<optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>;
  </synopsis>
  
         <para>
***************
*** 2000,2006 ****
  <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
--- 2000,2006 ----
  <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>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>;
  </synopsis>
       The record or row variable is successively assigned each row
       resulting from the <replaceable>query</replaceable> (which must be a
***************
*** 2039,2045 ****
  <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
--- 2039,2045 ----
  <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>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>;
  </synopsis>
       This is like the previous form, except that the source
       <command>SELECT</command> statement is specified as a string
diff -c -r --new-file pgsql/src/pl/plpgsql/src/gram.y 
pgsql.01/src/pl/plpgsql/src/gram.y
*** pgsql/src/pl/plpgsql/src/gram.y     2005-06-24 13:11:25.000000000 +0200
--- pgsql.01/src/pl/plpgsql/src/gram.y  2005-06-25 15:21:22.000000000 +0200
***************
*** 56,61 ****
--- 56,62 ----
                                                                                
           PLpgSQL_datum *initial_datum);
  static        void                     check_sql_expr(const char *stmt);
  static        void                     plpgsql_sql_error_callback(void *arg);
+ static void           check_labels(char *lbl, char *elbl, int lno);
  
  %}
  
***************
*** 81,86 ****
--- 82,93 ----
                        int  n_initvars;
                        int  *initvarnos;
                }                                               declhdr;
+               struct 
+               {
+                       char *label;
+                       int lineno;
+                       List *list;
+               }                                               loop_body;
                List                                    *list;
                PLpgSQL_type                    *dtype;
                PLpgSQL_datum                   *scalar;        /* a VAR, 
RECFIELD, or TRIGARG */
***************
*** 122,129 ****
  %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
--- 129,138 ----
  %type <str>           opt_lblname opt_label
  %type <str>           opt_exitlabel
  %type <str>           execsql_start
+ %type <str>           opt_lbltext opt_endlabel
  
! %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;
--- 257,268 ----
                                | ';'
                                ;
  
! pl_block              : decl_sect K_BEGIN lno proc_sect exception_sect K_END 
opt_endlabel
                                        {
                                                PLpgSQL_stmt_block *new;
  
+                                               check_labels($1.label, $7, $3);
+                                               
                                                new = 
palloc0(sizeof(PLpgSQL_stmt_block));
  
                                                new->cmd_type   = 
PLPGSQL_STMT_BLOCK;
***************
*** 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;
  
--- 799,814 ----
                                                new->cmd_type = 
PLPGSQL_STMT_LOOP;
                                                new->lineno   = $3;
                                                new->label        = $1;
!                                               new->body         = $4.list;
!                                               
!                                               check_labels($1, $4.label, 
$4.lineno);
                                                plpgsql_ns_pop();
  
                                                $$ = (PLpgSQL_stmt *)new;
                                        }
                                ;
  
! stmt_while            : opt_label K_WHILE lno expr_until_loop loop_body 
                                        {
                                                PLpgSQL_stmt_while *new;
  
***************
*** 805,812 ****
                                                new->lineno   = $3;
                                                new->label        = $1;
                                                new->cond         = $4;
!                                               new->body         = $5;
  
                                                plpgsql_ns_pop();
  
                                                $$ = (PLpgSQL_stmt *)new;
--- 817,826 ----
                                                new->lineno   = $3;
                                                new->label        = $1;
                                                new->cond         = $4;
!                                               new->body         = $5.list;
  
+                                               check_labels($1, $5.label, 
$5.lineno);
+                                                       
                                                plpgsql_ns_pop();
  
                                                $$ = (PLpgSQL_stmt *)new;
***************
*** 822,828 ****
  
                                                        new = 
(PLpgSQL_stmt_fori *) $3;
                                                        new->label        = $1;
!                                                       new->body         = $4;
                                                        $$ = (PLpgSQL_stmt *) 
new;
                                                }
                                                else if ($3->cmd_type == 
PLPGSQL_STMT_FORS)
--- 836,842 ----
  
                                                        new = 
(PLpgSQL_stmt_fori *) $3;
                                                        new->label        = $1;
!                                                       new->body         = 
$4.list;
                                                        $$ = (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
--- 845,851 ----
  
                                                        new = 
(PLpgSQL_stmt_fors *) $3;
                                                        new->label        = $1;
!                                                       new->body         = 
$4.list;
                                                        $$ = (PLpgSQL_stmt *) 
new;
                                                }
                                                else
***************
*** 841,851 ****
                                                        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();
                                        }
                                ;
--- 855,866 ----
                                                        Assert($3->cmd_type == 
PLPGSQL_STMT_DYNFORS);
                                                        new = 
(PLpgSQL_stmt_dynfors *) $3;
                                                        new->label        = $1;
!                                                       new->body         = 
$4.list;
                                                        $$ = (PLpgSQL_stmt *) 
new;
                                                }
  
                                                /* close namespace started in 
opt_label */
+                                               check_labels($1, $4.label, 
$4.lineno);
                                                plpgsql_ns_pop();
                                        }
                                ;
***************
*** 1245,1252 ****
                                        }
                                ;
  
! loop_body             : proc_sect K_END K_LOOP ';'
!                                       { $$ = $1; }
                                ;
  
  stmt_execsql  : execsql_start lno
--- 1260,1271 ----
                                        }
                                ;
  
! loop_body             : proc_sect lno K_END K_LOOP opt_endlabel ';'
!                                       { 
!                                               $$.list = $1;
!                                               $$.lineno = $2; 
!                                               $$.label = $5;  
!                                       }
                                ;
  
  stmt_execsql  : execsql_start lno
***************
*** 1608,1621 ****
                                        }
                                ;
  
  opt_exitlabel :
                                        { $$ = NULL; }
                                | T_LABEL
                                        {
-                                               char    *name;
- 
-                                               plpgsql_convert_ident(yytext, 
&name, 1);
-                                               $$ = name;
                                        }
                                | T_WORD
                                        {
--- 1627,1645 ----
                                        }
                                ;
  
+ opt_endlabel :                                
+                                       {
+                                               $$ = NULL;
+                                       }
+                               |  '<' '<' opt_lbltext '>' '>'
+                                       {
+                                               $$ = $3;
+                                       }
+                               ;
  opt_exitlabel :
                                        { $$ = NULL; }
                                | T_LABEL
                                        {
                                        }
                                | T_WORD
                                        {
***************
*** 1623,1628 ****
--- 1647,1662 ----
                                                yyerror("no such label");
                                        }
                                ;
+ opt_lbltext :                 T_LABEL
+                                       {
+                                               char * name;
+                                               plpgsql_convert_ident(yytext, 
&name, 1);
+                                               $$ = name;
+                                       }
+                               | T_WORD
+                                       {
+                                               yyerror("no such label");
+                                       }
  
  opt_exitcond  : ';'
                                        { $$ = NULL; }
***************
*** 1630,1635 ****
--- 1664,1671 ----
                                        { $$ = $2; }
                                ;
  
+ 
+ 
  opt_lblname           : T_WORD
                                        {
                                                char    *name;
***************
*** 2210,2213 ****
--- 2246,2267 ----
        errposition(0);
  }
  
+ static void 
+ check_labels(char *lbl, char *elbl, int lno)
+ {
+       if (elbl)
+       {
+               if (lbl == NULL)
+               {
+                       plpgsql_error_lineno = lno;
+                       yyerror("Can't to specify end label without begin 
label.");
+               }
+               if (strcmp(lbl, elbl) != 0)
+               {
+                       plpgsql_error_lineno = lno;
+                       yyerror("End label is defferent block/loop label");
+               }
+       }
+ }
+ 
  #include "pl_scan.c"
diff -c -r --new-file pgsql/src/test/regress/expected/plpgsql.out 
pgsql.01/src/test/regress/expected/plpgsql.out
*** pgsql/src/test/regress/expected/plpgsql.out 2005-06-24 13:11:38.000000000 
+0200
--- pgsql.01/src/test/regress/expected/plpgsql.out      2005-06-25 
15:23:17.000000000 +0200
***************
*** 2666,2668 ****
--- 2666,2711 ----
  drop function continue_test2();
  drop function continue_test3();
  drop table conttesttbl;
+ -- verbose end block and end loop
+ create function vfoo() 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;  
+ CREATE FUNCTION
+ create function vfoo2() returns void as $$
+ <<blbl>>
+ begin
+   for _i in 1 .. 10 loop
+     exit;
+   end loop <<flbl1>>;
+   <<flbl2>>
+   for _i in 1 .. 10 loop
+     exit flbl2;
+   end loop <<flbl3>>;
+ end <<blbl>>;
+ $$ language plpgsql;  
+ ERROR:  no such label at or near "flbl1" at character 107
+ LINE 6:   end loop <<flbl1>>;
+                      ^
+ select vfoo();
+  vfoo 
+ ------
+  
+ (1 row)
+ 
+ select fvoo2();
+ ERROR:  function fvoo2() does not exist
+ HINT:  No function matches the given name and argument types. You may need to 
add explicit type casts.
+ drop function vfoo();
+ DROP FUNCTION
+ drop function vfoo2();
+ ERROR:  function vfoo2() does not exist
diff -c -r --new-file pgsql/src/test/regress/sql/plpgsql.sql 
pgsql.01/src/test/regress/sql/plpgsql.sql
*** pgsql/src/test/regress/sql/plpgsql.sql      2005-06-24 13:11:35.000000000 
+0200
--- pgsql.01/src/test/regress/sql/plpgsql.sql   2005-06-25 14:10:30.000000000 
+0200
***************
*** 2232,2234 ****
--- 2232,2268 ----
  drop function continue_test2();
  drop function continue_test3();
  drop table conttesttbl;
+ 
+ -- verbose end block and end loop
+ create function vfoo() 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;  
+ 
+ create function vfoo2() returns void as $$
+ <<blbl>>
+ begin
+   for _i in 1 .. 10 loop
+     exit;
+   end loop <<flbl1>>;
+   <<flbl2>>
+   for _i in 1 .. 10 loop
+     exit flbl2;
+   end loop <<flbl3>>;
+ end <<blbl>>;
+ $$ language plpgsql;  
+ 
+ select vfoo();
+ select fvoo2();
+ 
+ drop function vfoo();
+ drop function vfoo2();
---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

               http://www.postgresql.org/docs/faq

Reply via email to