@ -186,7 +186,8 @@ static void check_raise_parameters(PLpgSQL_stmt_raise *stmt);
%type <forvariable> for_variable
%type <stmt> for_control
%type <str> any_identifier opt_block_label opt_label option_value
%type <str> any_identifier opt_block_label opt_loop_label opt_label
%type <str> option_value
%type <list> proc_sect stmt_elsifs stmt_else
%type <loop_body> loop_body
@ -535,7 +536,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull
$4->itemno, $1.name);
}
| decl_varname opt_scrollable K_CURSOR
{ plpgsql_ns_push($1.name); }
{ plpgsql_ns_push($1.name, PLPGSQL_LABEL_OTHER ); }
decl_cursor_args decl_is_for decl_cursor_query
{
PLpgSQL_var *new;
@ -1218,7 +1219,7 @@ opt_case_else :
}
;
stmt_loop : opt_block _label K_LOOP loop_body
stmt_loop : opt_loop _label K_LOOP loop_body
{
PLpgSQL_stmt_loop *new;
@ -1235,7 +1236,7 @@ stmt_loop : opt_block_label K_LOOP loop_body
}
;
stmt_while : opt_block _label K_WHILE expr_until_loop loop_body
stmt_while : opt_loop _label K_WHILE expr_until_loop loop_body
{
PLpgSQL_stmt_while *new;
@ -1253,7 +1254,7 @@ stmt_while : opt_block_label K_WHILE expr_until_loop loop_body
}
;
stmt_for : opt_block _label K_FOR for_control loop_body
stmt_for : opt_loop _label K_FOR for_control loop_body
{
/* This runs after we've scanned the loop body */
if ($3->cmd_type == PLPGSQL_STMT_FORI)
@ -1282,7 +1283,7 @@ stmt_for : opt_block_label K_FOR for_control loop_body
}
check_labels($1, $4.end_label, $4.end_label_location);
/* close namespace started in opt_block _label */
/* close namespace started in opt_loop _label */
plpgsql_ns_pop();
}
;
@ -1603,7 +1604,7 @@ for_variable : T_DATUM
}
;
stmt_foreach_a : opt_block _label K_FOREACH for_variable foreach_slice K_IN K_ARRAY expr_until_loop loop_body
stmt_foreach_a : opt_loop _label K_FOREACH for_variable foreach_slice K_IN K_ARRAY expr_until_loop loop_body
{
PLpgSQL_stmt_foreach_a *new;
@ -1666,6 +1667,42 @@ stmt_exit : exit_type opt_label opt_exitcond
new->label = $2;
new->cond = $3;
if ($2)
{
/* We have a label, so verify it exists */
PLpgSQL_nsitem *label;
label = plpgsql_ns_lookup_label(plpgsql_ns_top(), $2);
if (label == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("label \"%s\" does not exist",
$2),
parser_errposition(@2)));
/* CONTINUE only allows loop labels */
if (label->itemno != PLPGSQL_LABEL_LOOP && !$1)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("block label \"%s\" cannot be used in CONTINUE",
$2),
parser_errposition(@2)));
}
else
{
/*
* No label, so make sure there is some loop (an
* unlabelled EXIT does not match a block, so this
* is the same test for both EXIT and CONTINUE)
*/
if (plpgsql_ns_find_nearest_loop(plpgsql_ns_top()) == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
/* translator: %s is EXIT or CONTINUE */
errmsg("%s cannot be used outside a loop",
plpgsql_stmt_typename((PLpgSQL_stmt *) new)),
parser_errposition(@1)));
}
$$ = (PLpgSQL_stmt *)new;
}
;
@ -2290,12 +2327,24 @@ expr_until_loop :
opt_block_label :
{
plpgsql_ns_push(NULL);
plpgsql_ns_push(NULL, PLPGSQL_LABEL_BLOCK);
$$ = NULL;
}
| LESS_LESS any_identifier GREATER_GREATER
{
plpgsql_ns_push($2, PLPGSQL_LABEL_BLOCK);
$$ = $2;
}
;
opt_loop_label :
{
plpgsql_ns_push(NULL, PLPGSQL_LABEL_LOOP);
$$ = NULL;
}
| LESS_LESS any_identifier GREATER_GREATER
{
plpgsql_ns_push($2);
plpgsql_ns_push($2, PLPGSQL_LABEL_LOOP );
$$ = $2;
}
;
@ -2306,8 +2355,7 @@ opt_label :
}
| any_identifier
{
if (plpgsql_ns_lookup_label(plpgsql_ns_top(), $1) == NULL)
yyerror("label does not exist");
/* label validity will be checked by outer production */
$$ = $1;
}
;