4
4
* procedural language
5
5
*
6
6
* 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 $
8
8
*
9
9
* This software is copyrighted by Jan Wieck - Hamburg.
10
10
*
@@ -56,6 +56,8 @@ static PLpgSQL_row *read_into_scalar_list(const char *initial_name,
56
56
PLpgSQL_datum *initial_datum);
57
57
static void check_sql_expr (const char *stmt);
58
58
static void plpgsql_sql_error_callback (void *arg);
59
+ static void check_labels (const char *start_label,
60
+ const char *end_label);
59
61
60
62
%}
61
63
@@ -69,7 +71,7 @@ static void plpgsql_sql_error_callback(void *arg);
69
71
int lineno;
70
72
} varname;
71
73
struct
72
- {
74
+ {
73
75
char *name;
74
76
int lineno;
75
77
PLpgSQL_rec *rec;
@@ -81,6 +83,11 @@ static void plpgsql_sql_error_callback(void *arg);
81
83
int n_initvars;
82
84
int *initvarnos;
83
85
} declhdr;
86
+ struct
87
+ {
88
+ char *end_label;
89
+ List *stmts;
90
+ } loop_body;
84
91
List *list;
85
92
PLpgSQL_type *dtype;
86
93
PLpgSQL_datum *scalar; /* a VAR, RECFIELD, or TRIGARG */
@@ -119,11 +126,11 @@ static void plpgsql_sql_error_callback(void *arg);
119
126
%type <forvariable> for_variable
120
127
%type <stmt> for_control
121
128
122
- %type <str> opt_lblname opt_label
123
- %type <str> opt_exitlabel
129
+ %type <str> opt_lblname opt_block_label opt_label
124
130
%type <str> execsql_start
125
131
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
127
134
%type <stmt> proc_stmt pl_block
128
135
%type <stmt> stmt_assign stmt_if stmt_loop stmt_while stmt_exit
129
136
%type <stmt> stmt_return stmt_return_next stmt_raise stmt_execsql
@@ -248,7 +255,7 @@ opt_semi :
248
255
| ' ;'
249
256
;
250
257
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
252
259
{
253
260
PLpgSQL_stmt_block *new ;
254
261
@@ -262,30 +269,31 @@ pl_block : decl_sect K_BEGIN lno proc_sect exception_sect K_END
262
269
new ->body = $4 ;
263
270
new ->exceptions = $5 ;
264
271
272
+ check_labels ($1 .label, $7 );
265
273
plpgsql_ns_pop ();
266
274
267
275
$$ = (PLpgSQL_stmt *)new ;
268
276
}
269
277
;
270
278
271
279
272
- decl_sect : opt_label
280
+ decl_sect : opt_block_label
273
281
{
274
282
plpgsql_ns_setlocal (false );
275
283
$$ .label = $1 ;
276
284
$$ .n_initvars = 0 ;
277
285
$$ .initvarnos = NULL ;
278
286
plpgsql_add_initdatums (NULL );
279
287
}
280
- | opt_label decl_start
288
+ | opt_block_label decl_start
281
289
{
282
290
plpgsql_ns_setlocal (false );
283
291
$$ .label = $1 ;
284
292
$$ .n_initvars = 0 ;
285
293
$$ .initvarnos = NULL ;
286
294
plpgsql_add_initdatums (NULL );
287
295
}
288
- | opt_label decl_start decl_stmts
296
+ | opt_block_label decl_start decl_stmts
289
297
{
290
298
plpgsql_ns_setlocal (false );
291
299
if ($3 != NULL )
@@ -409,7 +417,7 @@ decl_cursor_query :
409
417
plpgsql_ns_setlocal (false );
410
418
query = read_sql_stmt(" " );
411
419
plpgsql_ns_setlocal (true );
412
-
420
+
413
421
$$ = query;
414
422
}
415
423
;
@@ -757,7 +765,7 @@ stmt_else :
757
765
* ... ...
758
766
* ELSE ELSE
759
767
* ... ...
760
- * END IF END IF
768
+ * END IF END IF
761
769
* END IF
762
770
*/
763
771
PLpgSQL_stmt_if *new_if;
@@ -776,27 +784,28 @@ stmt_else :
776
784
777
785
| K_ELSE proc_sect
778
786
{
779
- $$ = $2 ;
787
+ $$ = $2 ;
780
788
}
781
789
;
782
790
783
- stmt_loop : opt_label K_LOOP lno loop_body
791
+ stmt_loop : opt_block_label K_LOOP lno loop_body
784
792
{
785
793
PLpgSQL_stmt_loop *new ;
786
794
787
795
new = palloc0(sizeof (PLpgSQL_stmt_loop));
788
796
new ->cmd_type = PLPGSQL_STMT_LOOP;
789
797
new ->lineno = $3 ;
790
798
new ->label = $1 ;
791
- new ->body = $4 ;
799
+ new ->body = $4 .stmts ;
792
800
801
+ check_labels ($1 , $4 .end_label);
793
802
plpgsql_ns_pop ();
794
803
795
804
$$ = (PLpgSQL_stmt *)new ;
796
805
}
797
806
;
798
807
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
800
809
{
801
810
PLpgSQL_stmt_while *new ;
802
811
@@ -805,15 +814,16 @@ stmt_while : opt_label K_WHILE lno expr_until_loop loop_body
805
814
new ->lineno = $3 ;
806
815
new ->label = $1 ;
807
816
new ->cond = $4 ;
808
- new ->body = $5 ;
817
+ new ->body = $5 .stmts ;
809
818
819
+ check_labels ($1 , $5 .end_label);
810
820
plpgsql_ns_pop ();
811
821
812
822
$$ = (PLpgSQL_stmt *)new ;
813
823
}
814
824
;
815
825
816
- stmt_for : opt_label K_FOR for_control loop_body
826
+ stmt_for : opt_block_label K_FOR for_control loop_body
817
827
{
818
828
/* This runs after we've scanned the loop body */
819
829
if ($3 ->cmd_type == PLPGSQL_STMT_FORI)
@@ -822,7 +832,7 @@ stmt_for : opt_label K_FOR for_control loop_body
822
832
823
833
new = (PLpgSQL_stmt_fori *) $3 ;
824
834
new ->label = $1 ;
825
- new ->body = $4 ;
835
+ new ->body = $4 .stmts ;
826
836
$$ = (PLpgSQL_stmt *) new ;
827
837
}
828
838
else if ($3 ->cmd_type == PLPGSQL_STMT_FORS)
@@ -831,7 +841,7 @@ stmt_for : opt_label K_FOR for_control loop_body
831
841
832
842
new = (PLpgSQL_stmt_fors *) $3 ;
833
843
new ->label = $1 ;
834
- new ->body = $4 ;
844
+ new ->body = $4 .stmts ;
835
845
$$ = (PLpgSQL_stmt *) new ;
836
846
}
837
847
else
@@ -841,10 +851,11 @@ stmt_for : opt_label K_FOR for_control loop_body
841
851
Assert ($3 ->cmd_type == PLPGSQL_STMT_DYNFORS);
842
852
new = (PLpgSQL_stmt_dynfors *) $3 ;
843
853
new ->label = $1 ;
844
- new ->body = $4 ;
854
+ new ->body = $4 .stmts ;
845
855
$$ = (PLpgSQL_stmt *) new ;
846
856
}
847
857
858
+ check_labels ($1 , $4 .end_label);
848
859
/* close namespace started in opt_label */
849
860
plpgsql_ns_pop ();
850
861
}
@@ -1037,7 +1048,7 @@ stmt_select : K_SELECT lno
1037
1048
}
1038
1049
;
1039
1050
1040
- stmt_exit : exit_type lno opt_exitlabel opt_exitcond
1051
+ stmt_exit : exit_type lno opt_label opt_exitcond
1041
1052
{
1042
1053
PLpgSQL_stmt_exit *new ;
1043
1054
@@ -1245,8 +1256,11 @@ raise_level : K_EXCEPTION
1245
1256
}
1246
1257
;
1247
1258
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
+ }
1250
1264
;
1251
1265
1252
1266
stmt_execsql : execsql_start lno
@@ -1262,7 +1276,7 @@ stmt_execsql : execsql_start lno
1262
1276
}
1263
1277
;
1264
1278
1265
- stmt_dynexecute : K_EXECUTE lno
1279
+ stmt_dynexecute : K_EXECUTE lno
1266
1280
{
1267
1281
PLpgSQL_stmt_dynexecute *new ;
1268
1282
PLpgSQL_expr *expr;
@@ -1418,7 +1432,7 @@ stmt_open : K_OPEN lno cursor_varptr
1418
1432
errmsg(" cursor \" %s\" has no arguments" ,
1419
1433
$3 ->refname)));
1420
1434
}
1421
-
1435
+
1422
1436
if (tok != ' ;' )
1423
1437
{
1424
1438
plpgsql_error_lineno = plpgsql_scanner_lineno();
@@ -1596,7 +1610,7 @@ expr_until_loop :
1596
1610
{ $$ = plpgsql_read_expression(K_LOOP, " LOOP" ); }
1597
1611
;
1598
1612
1599
- opt_label :
1613
+ opt_block_label :
1600
1614
{
1601
1615
plpgsql_ns_push (NULL );
1602
1616
$$ = NULL ;
@@ -1608,14 +1622,15 @@ opt_label :
1608
1622
}
1609
1623
;
1610
1624
1611
- opt_exitlabel :
1612
- { $$ = NULL ; }
1625
+ opt_label :
1626
+ {
1627
+ $$ = NULL ;
1628
+ }
1613
1629
| T_LABEL
1614
1630
{
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;
1619
1634
}
1620
1635
| T_WORD
1621
1636
{
@@ -2210,4 +2225,29 @@ plpgsql_sql_error_callback(void *arg)
2210
2225
errposition (0 );
2211
2226
}
2212
2227
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
+
2213
2253
#include " pl_scan.c"
0 commit comments