44 * procedural language
55 *
66 * IDENTIFICATION
7- * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.78 2005/07/01 17:40:29 momjian Exp $
7+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.79 2005/07/02 08:59:47 neilc Exp $
88 *
99 * This software is copyrighted by Jan Wieck - Hamburg.
1010 *
@@ -56,6 +56,8 @@ staticPLpgSQL_row*read_into_scalar_list(const char *initial_name,
5656 PLpgSQL_datum *initial_datum);
5757static void check_sql_expr (const char *stmt);
5858static void plpgsql_sql_error_callback (void *arg);
59+ static void check_labels (const char *start_label,
60+ const char *end_label);
5961
6062%}
6163
@@ -69,7 +71,7 @@ staticvoid plpgsql_sql_error_callback(void *arg);
6971int lineno;
7072}varname;
7173struct
72- {
74+ {
7375char *name;
7476int lineno;
7577PLpgSQL_rec *rec;
@@ -81,6 +83,11 @@ staticvoid plpgsql_sql_error_callback(void *arg);
8183int n_initvars;
8284int *initvarnos;
8385}declhdr;
86+ struct
87+ {
88+ char *end_label;
89+ List *stmts;
90+ }loop_body;
8491List*list;
8592PLpgSQL_type*dtype;
8693PLpgSQL_datum*scalar;/* a VAR, RECFIELD, or TRIGARG*/
@@ -119,11 +126,11 @@ staticvoid plpgsql_sql_error_callback(void *arg);
119126%type <forvariable> for_variable
120127%type <stmt> for_control
121128
122- %type <str> opt_lblname opt_label
123- %type <str> opt_exitlabel
129+ %type <str> opt_lblname opt_block_label opt_label
124130%type <str> execsql_start
125131
126- %type <list> proc_sect proc_stmts stmt_else loop_body
132+ %type <list> proc_sect proc_stmts stmt_else
133+ %type <loop_body> loop_body
127134%type <stmt> proc_stmt pl_block
128135%type <stmt> stmt_assign stmt_if stmt_loop stmt_while stmt_exit
129136%type <stmt> stmt_return stmt_return_next stmt_raise stmt_execsql
@@ -248,7 +255,7 @@ opt_semi:
248255| ' ;'
249256;
250257
251- pl_block :decl_sect K_BEGIN lno proc_sect exception_sect K_END
258+ pl_block :decl_sect K_BEGIN lno proc_sect exception_sect K_END opt_label
252259{
253260PLpgSQL_stmt_block *new ;
254261
@@ -262,30 +269,31 @@ pl_block: decl_sect K_BEGIN lno proc_sect exception_sect K_END
262269new ->body=$4 ;
263270new ->exceptions=$5 ;
264271
272+ check_labels ($1 .label, $7 );
265273plpgsql_ns_pop ();
266274
267275$$ = (PLpgSQL_stmt *)new ;
268276}
269277;
270278
271279
272- decl_sect :opt_label
280+ decl_sect :opt_block_label
273281{
274282plpgsql_ns_setlocal (false );
275283$$ .label =$1 ;
276284$$ .n_initvars =0 ;
277285$$ .initvarnos =NULL ;
278286plpgsql_add_initdatums (NULL );
279287}
280- | opt_label decl_start
288+ | opt_block_label decl_start
281289{
282290plpgsql_ns_setlocal (false );
283291$$ .label =$1 ;
284292$$ .n_initvars =0 ;
285293$$ .initvarnos =NULL ;
286294plpgsql_add_initdatums (NULL );
287295}
288- | opt_label decl_start decl_stmts
296+ | opt_block_label decl_start decl_stmts
289297{
290298plpgsql_ns_setlocal (false );
291299if ($3 !=NULL )
@@ -409,7 +417,7 @@ decl_cursor_query :
409417plpgsql_ns_setlocal (false );
410418query = read_sql_stmt(" " );
411419plpgsql_ns_setlocal (true );
412-
420+
413421$$ = query;
414422}
415423;
@@ -757,7 +765,7 @@ stmt_else:
757765 * ... ...
758766 * ELSE ELSE
759767 * ... ...
760- * END IF END IF
768+ * END IF END IF
761769 * END IF
762770*/
763771PLpgSQL_stmt_if *new_if;
@@ -776,27 +784,28 @@ stmt_else:
776784
777785| K_ELSE proc_sect
778786{
779- $$ =$2 ;
787+ $$ =$2 ;
780788}
781789;
782790
783- stmt_loop :opt_label K_LOOP lno loop_body
791+ stmt_loop :opt_block_label K_LOOP lno loop_body
784792{
785793PLpgSQL_stmt_loop *new ;
786794
787795new = palloc0(sizeof (PLpgSQL_stmt_loop));
788796new ->cmd_type = PLPGSQL_STMT_LOOP;
789797new ->lineno =$3 ;
790798new ->label =$1 ;
791- new ->body =$4 ;
799+ new ->body =$4 .stmts ;
792800
801+ check_labels ($1 , $4 .end_label);
793802plpgsql_ns_pop ();
794803
795804$$ = (PLpgSQL_stmt *)new ;
796805}
797806;
798807
799- stmt_while :opt_label K_WHILE lno expr_until_loop loop_body
808+ stmt_while :opt_block_label K_WHILE lno expr_until_loop loop_body
800809{
801810PLpgSQL_stmt_while *new ;
802811
@@ -805,15 +814,16 @@ stmt_while: opt_label K_WHILE lno expr_until_loop loop_body
805814new ->lineno =$3 ;
806815new ->label =$1 ;
807816new ->cond =$4 ;
808- new ->body =$5 ;
817+ new ->body =$5 .stmts ;
809818
819+ check_labels ($1 , $5 .end_label);
810820plpgsql_ns_pop ();
811821
812822$$ = (PLpgSQL_stmt *)new ;
813823}
814824;
815825
816- stmt_for :opt_label K_FOR for_control loop_body
826+ stmt_for :opt_block_label K_FOR for_control loop_body
817827{
818828/* This runs after we've scanned the loop body*/
819829if ($3 ->cmd_type == PLPGSQL_STMT_FORI)
@@ -822,7 +832,7 @@ stmt_for: opt_label K_FOR for_control loop_body
822832
823833new = (PLpgSQL_stmt_fori *)$3 ;
824834new ->label =$1 ;
825- new ->body =$4 ;
835+ new ->body =$4 .stmts ;
826836$$ = (PLpgSQL_stmt *)new ;
827837}
828838else if ($3 ->cmd_type == PLPGSQL_STMT_FORS)
@@ -831,7 +841,7 @@ stmt_for: opt_label K_FOR for_control loop_body
831841
832842new = (PLpgSQL_stmt_fors *)$3 ;
833843new ->label =$1 ;
834- new ->body =$4 ;
844+ new ->body =$4 .stmts ;
835845$$ = (PLpgSQL_stmt *)new ;
836846}
837847else
@@ -841,10 +851,11 @@ stmt_for: opt_label K_FOR for_control loop_body
841851Assert ($3 ->cmd_type == PLPGSQL_STMT_DYNFORS);
842852new = (PLpgSQL_stmt_dynfors *)$3 ;
843853new ->label =$1 ;
844- new ->body =$4 ;
854+ new ->body =$4 .stmts ;
845855$$ = (PLpgSQL_stmt *)new ;
846856}
847857
858+ check_labels ($1 , $4 .end_label);
848859/* close namespace started in opt_label*/
849860plpgsql_ns_pop ();
850861}
@@ -1037,7 +1048,7 @@ stmt_select: K_SELECT lno
10371048}
10381049;
10391050
1040- stmt_exit :exit_type lno opt_exitlabel opt_exitcond
1051+ stmt_exit :exit_type lno opt_label opt_exitcond
10411052{
10421053PLpgSQL_stmt_exit *new ;
10431054
@@ -1245,8 +1256,11 @@ raise_level: K_EXCEPTION
12451256}
12461257;
12471258
1248- loop_body :proc_sect K_END K_LOOP ' ;'
1249- {$$ =$1 ; }
1259+ loop_body :proc_sect K_END K_LOOP opt_label ' ;'
1260+ {
1261+ $$ .stmts =$1 ;
1262+ $$ .end_label =$4 ;
1263+ }
12501264;
12511265
12521266stmt_execsql :execsql_start lno
@@ -1262,7 +1276,7 @@ stmt_execsql: execsql_start lno
12621276}
12631277;
12641278
1265- stmt_dynexecute :K_EXECUTE lno
1279+ stmt_dynexecute :K_EXECUTE lno
12661280{
12671281PLpgSQL_stmt_dynexecute *new ;
12681282PLpgSQL_expr *expr;
@@ -1418,7 +1432,7 @@ stmt_open: K_OPEN lno cursor_varptr
14181432 errmsg(" cursor\" %s\" has no arguments" ,
14191433$3 ->refname)));
14201434}
1421-
1435+
14221436if (tok !=' ;' )
14231437{
14241438plpgsql_error_lineno = plpgsql_scanner_lineno();
@@ -1596,7 +1610,7 @@ expr_until_loop :
15961610{$$ = plpgsql_read_expression(K_LOOP," LOOP" ); }
15971611;
15981612
1599- opt_label :
1613+ opt_block_label :
16001614{
16011615plpgsql_ns_push (NULL );
16021616$$ =NULL ;
@@ -1608,14 +1622,15 @@ opt_label:
16081622}
16091623;
16101624
1611- opt_exitlabel :
1612- {$$ =NULL ; }
1625+ opt_label :
1626+ {
1627+ $$ =NULL ;
1628+ }
16131629| T_LABEL
16141630{
1615- char *name;
1616-
1617- plpgsql_convert_ident (yytext, &name,1 );
1618- $$ = name;
1631+ char *label_name;
1632+ plpgsql_convert_ident (yytext, &label_name,1 );
1633+ $$ = label_name;
16191634}
16201635| T_WORD
16211636{
@@ -2210,4 +2225,29 @@ plpgsql_sql_error_callback(void *arg)
22102225errposition (0 );
22112226}
22122227
2228+ static void
2229+ check_labels (const char *start_label,const char *end_label)
2230+ {
2231+ if (end_label)
2232+ {
2233+ if (!start_label)
2234+ {
2235+ plpgsql_error_lineno =plpgsql_scanner_lineno ();
2236+ ereport (ERROR,
2237+ (errcode (ERRCODE_SYNTAX_ERROR),
2238+ errmsg (" end label\" %s\" specified for unlabelled block" ,
2239+ end_label)));
2240+ }
2241+
2242+ if (strcmp (start_label, end_label) !=0 )
2243+ {
2244+ plpgsql_error_lineno =plpgsql_scanner_lineno ();
2245+ ereport (ERROR,
2246+ (errcode (ERRCODE_SYNTAX_ERROR),
2247+ errmsg (" end label\" %s\" differs from block's label\" %s\" " ,
2248+ end_label, start_label)));
2249+ }
2250+ }
2251+ }
2252+
22132253#include " pl_scan.c"