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 ****
declarations
BEGIN
statements
! END;
--- 456,462 ----
declarations
BEGIN
statements
! END <<label>> ;
***************
*** 1792,1798 ****
<<label>>
LOOP
statements
! END LOOP;
--- 1792,1798 ----
<<label>>
LOOP
statements
! END LOOP <<label>>;
***************
*** 1923,1929 ****
<<label>>
WHILE expression LOOP
statements
! END LOOP;
--- 1923,1929 ----
<<label>>
WHILE expression LOOP
statements
! END LOOP <<label>>;
***************
*** 2000,2006 ****
<<label>>
FOR record_or_row IN query LOOP
statements
! END LOOP;
The record or row variable is successively assigned each row
resulting from the query (which must be a
--- 2000,2006 ----
<<label>>
FOR record_or_row IN query LOOP
statements
! END LOOP <<label>>;
The record or row variable is successively assigned each row
resulting from the query (which must be a
***************
*** 2039,2045 ****
<<label>>
FOR record_or_row IN EXECUTE text_expression LOOP
statements
! END LOOP;
This is like the previous form, except that the source
SELECT statement is specified as a string
--- 2039,2045 ----
<<label>>
FOR record_or_row IN EXECUTE text_expression LOOP
statements
! END LOOP <<label>>;
This is like the previous form, except that the source
SELECT 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 opt_lblname opt_label
%type opt_exitlabel
%type execsql_start
! %type proc_sect proc_stmts stmt_else loop_body
%type proc_stmt pl_block
%type stmt_assign stmt_if stmt_loop stmt_while stmt_exit
%type stmt_return stmt_return_next stmt_raise stmt_execsql
--- 129,138 ----
%type opt_lblname opt_label
%type opt_exitlabel
%type execsql_start
+ %type opt_lbltext opt_endlabel
! %type proc_sect proc_stmts stmt_else
! %type loop_body
%type proc_stmt pl_block
%type stmt_assign stmt_if stmt_loop stmt_while stmt_exit
%type 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 $$
+ <>
+ begin
+ <>
+ for _i in 1 .. 10 loop
+ exit flbl1;
+ end loop <>;
+ <>
+ for _i in 1 .. 10 loop
+ exit flbl2;
+ end loop;
+ end <>;
+ $$ language plpgsql;
+ CREATE FUNCTION
+ create function vfoo2() returns void as $$
+ <>
+ begin
+ for _i in 1 .. 10 loop
+ exit;
+ end loop <>;
+ <>
+ for _i in 1 .. 10 loop
+ exit flbl2;
+ end loop <>;
+ end <>;
+ $$ language plpgsql;
+ ERROR: no such label at or near "flbl1" at character 107
+ LINE 6: end loop <>;
+ ^
+ 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 $$
+ <>
+ begin
+ <>
+ for _i in 1 .. 10 loop
+ exit flbl1;
+ end loop <>;
+ <>
+ for _i in 1 .. 10 loop
+ exit flbl2;
+ end loop;
+ end <>;
+ $$ language plpgsql;
+
+ create function vfoo2() returns void as $$
+ <>
+ begin
+ for _i in 1 .. 10 loop
+ exit;
+ end loop <>;
+ <>
+ for _i in 1 .. 10 loop
+ exit flbl2;
+ end loop <>;
+ end <>;
+ $$ language plpgsql;
+
+ select vfoo();
+ select fvoo2();
+
+ drop function vfoo();
+ drop function vfoo2();