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