Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitc425dcb

Browse files
author
Neil Conway
committed
In PL/PgSQL, allow a block's label to be optionally specified at the
end of the block:<<label>>begin ...end label;Similarly for loops. This is per PL/SQL. Update the documentation andadd regression tests. Patch from Pavel Stehule, code review by NeilConway.
1 parent784b948 commitc425dcb

File tree

4 files changed

+197
-53
lines changed

4 files changed

+197
-53
lines changed

‎doc/src/sgml/plpgsql.sgml

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.74 2005/06/22 01:35:02 neilc Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.75 2005/07/02 08:59:47 neilc Exp $
33
-->
44

55
<chapter id="plpgsql">
@@ -456,7 +456,7 @@ a_output := a_output || $$ if v_$$ || referrer_keys.kind || $$ like '$$
456456
<replaceable>declarations</replaceable> </optional>
457457
BEGIN
458458
<replaceable>statements</replaceable>
459-
END;
459+
END <optional> <replaceable>label</replaceable> </optional>;
460460
</synopsis>
461461
</para>
462462

@@ -1789,18 +1789,19 @@ END IF;
17891789
<title><literal>LOOP</></title>
17901790

17911791
<synopsis>
1792-
<optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
1792+
<optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
17931793
LOOP
17941794
<replaceable>statements</replaceable>
1795-
END LOOP;
1795+
END LOOP <optional> <replaceable>label</replaceable> </optional>;
17961796
</synopsis>
17971797

17981798
<para>
1799-
<literal>LOOP</> defines an unconditional loop that is repeated indefinitely
1800-
until terminated by an <literal>EXIT</> or <command>RETURN</command>
1801-
statement. The optional label can be used by <literal>EXIT</> statements in
1802-
nested loops to specify which level of nesting should be
1803-
terminated.
1799+
<literal>LOOP</> defines an unconditional loop that is repeated
1800+
indefinitely until terminated by an <literal>EXIT</> or
1801+
<command>RETURN</command> statement. The optional
1802+
<replaceable>label</replaceable> can be used by <literal>EXIT</>
1803+
and <literal>CONTINUE</literal> statements in nested loops to
1804+
specify which loop the statement should be applied to.
18041805
</para>
18051806
</sect3>
18061807

@@ -1920,10 +1921,10 @@ END LOOP;
19201921
</indexterm>
19211922

19221923
<synopsis>
1923-
<optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
1924+
<optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
19241925
WHILE <replaceable>expression</replaceable> LOOP
19251926
<replaceable>statements</replaceable>
1926-
END LOOP;
1927+
END LOOP <optional> <replaceable>label</replaceable> </optional>;
19271928
</synopsis>
19281929

19291930
<para>
@@ -1951,10 +1952,10 @@ END LOOP;
19511952
<title><literal>FOR</> (integer variant)</title>
19521953

19531954
<synopsis>
1954-
<optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
1955+
<optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
19551956
FOR <replaceable>name</replaceable> IN <optional> REVERSE </optional> <replaceable>expression</replaceable> .. <replaceable>expression</replaceable> LOOP
19561957
<replaceable>statements</replaceable>
1957-
END LOOP;
1958+
END LOOP <optional> <replaceable>labal</replaceable> </optional>;
19581959
</synopsis>
19591960

19601961
<para>
@@ -1997,10 +1998,10 @@ END LOOP;
19971998
the results of a query and manipulate that data
19981999
accordingly. The syntax is:
19992000
<synopsis>
2000-
<optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
2001+
<optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
20012002
FOR <replaceable>record_or_row</replaceable> IN <replaceable>query</replaceable> LOOP
20022003
<replaceable>statements</replaceable>
2003-
END LOOP;
2004+
END LOOP <optional> <replaceable>label</replaceable> </optional>;
20042005
</synopsis>
20052006
The record or row variable is successively assigned each row
20062007
resulting from the <replaceable>query</replaceable> (which must be a
@@ -2036,10 +2037,10 @@ $$ LANGUAGE plpgsql;
20362037
The <literal>FOR-IN-EXECUTE</> statement is another way to iterate over
20372038
rows:
20382039
<synopsis>
2039-
<optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
2040+
<optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
20402041
FOR <replaceable>record_or_row</replaceable> IN EXECUTE <replaceable>text_expression</replaceable> LOOP
20412042
<replaceable>statements</replaceable>
2042-
END LOOP;
2043+
END LOOP <optional> <replaceable>label</replaceable> </optional>;
20432044
</synopsis>
20442045
This is like the previous form, except that the source
20452046
<command>SELECT</command> statement is specified as a string

‎src/pl/plpgsql/src/gram.y

Lines changed: 72 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
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);
5757
staticvoidcheck_sql_expr(constchar *stmt);
5858
staticvoidplpgsql_sql_error_callback(void *arg);
59+
staticvoidcheck_labels(constchar *start_label,
60+
constchar *end_label);
5961

6062
%}
6163

@@ -69,7 +71,7 @@ staticvoid plpgsql_sql_error_callback(void *arg);
6971
int lineno;
7072
}varname;
7173
struct
72-
{
74+
{
7375
char *name;
7476
int lineno;
7577
PLpgSQL_rec *rec;
@@ -81,6 +83,11 @@ staticvoid plpgsql_sql_error_callback(void *arg);
8183
int n_initvars;
8284
int *initvarnos;
8385
}declhdr;
86+
struct
87+
{
88+
char *end_label;
89+
List *stmts;
90+
}loop_body;
8491
List*list;
8592
PLpgSQL_type*dtype;
8693
PLpgSQL_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_lblnameopt_label
123-
%type<str>opt_exitlabel
129+
%type<str>opt_lblnameopt_block_labelopt_label
124130
%type<str>execsql_start
125131

126-
%type<list>proc_sectproc_stmtsstmt_elseloop_body
132+
%type<list>proc_sectproc_stmtsstmt_else
133+
%type<loop_body>loop_body
127134
%type<stmt>proc_stmtpl_block
128135
%type<stmt>stmt_assignstmt_ifstmt_loopstmt_whilestmt_exit
129136
%type<stmt>stmt_returnstmt_return_nextstmt_raisestmt_execsql
@@ -248,7 +255,7 @@ opt_semi:
248255
|';'
249256
;
250257

251-
pl_block:decl_sectK_BEGINlnoproc_sectexception_sectK_END
258+
pl_block:decl_sectK_BEGINlnoproc_sectexception_sectK_ENDopt_label
252259
{
253260
PLpgSQL_stmt_block *new;
254261

@@ -262,30 +269,31 @@ pl_block: decl_sect K_BEGIN lno proc_sect exception_sect K_END
262269
new->body=$4;
263270
new->exceptions=$5;
264271

272+
check_labels($1.label, $7);
265273
plpgsql_ns_pop();
266274

267275
$$ = (PLpgSQL_stmt *)new;
268276
}
269277
;
270278

271279

272-
decl_sect:opt_label
280+
decl_sect:opt_block_label
273281
{
274282
plpgsql_ns_setlocal(false);
275283
$$.label =$1;
276284
$$.n_initvars =0;
277285
$$.initvarnos =NULL;
278286
plpgsql_add_initdatums(NULL);
279287
}
280-
|opt_labeldecl_start
288+
|opt_block_labeldecl_start
281289
{
282290
plpgsql_ns_setlocal(false);
283291
$$.label =$1;
284292
$$.n_initvars =0;
285293
$$.initvarnos =NULL;
286294
plpgsql_add_initdatums(NULL);
287295
}
288-
|opt_labeldecl_startdecl_stmts
296+
|opt_block_labeldecl_startdecl_stmts
289297
{
290298
plpgsql_ns_setlocal(false);
291299
if ($3 !=NULL)
@@ -409,7 +417,7 @@ decl_cursor_query :
409417
plpgsql_ns_setlocal(false);
410418
query = read_sql_stmt("");
411419
plpgsql_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
*/
763771
PLpgSQL_stmt_if *new_if;
@@ -776,27 +784,28 @@ stmt_else:
776784

777785
|K_ELSEproc_sect
778786
{
779-
$$ =$2;
787+
$$ =$2;
780788
}
781789
;
782790

783-
stmt_loop:opt_labelK_LOOPlnoloop_body
791+
stmt_loop:opt_block_labelK_LOOPlnoloop_body
784792
{
785793
PLpgSQL_stmt_loop *new;
786794

787795
new = palloc0(sizeof(PLpgSQL_stmt_loop));
788796
new->cmd_type = PLPGSQL_STMT_LOOP;
789797
new->lineno =$3;
790798
new->label =$1;
791-
new->body =$4;
799+
new->body =$4.stmts;
792800

801+
check_labels($1, $4.end_label);
793802
plpgsql_ns_pop();
794803

795804
$$ = (PLpgSQL_stmt *)new;
796805
}
797806
;
798807

799-
stmt_while:opt_labelK_WHILElnoexpr_until_looploop_body
808+
stmt_while:opt_block_labelK_WHILElnoexpr_until_looploop_body
800809
{
801810
PLpgSQL_stmt_while *new;
802811

@@ -805,15 +814,16 @@ stmt_while: opt_label K_WHILE lno expr_until_loop loop_body
805814
new->lineno =$3;
806815
new->label =$1;
807816
new->cond =$4;
808-
new->body =$5;
817+
new->body =$5.stmts;
809818

819+
check_labels($1, $5.end_label);
810820
plpgsql_ns_pop();
811821

812822
$$ = (PLpgSQL_stmt *)new;
813823
}
814824
;
815825

816-
stmt_for:opt_labelK_FORfor_controlloop_body
826+
stmt_for:opt_block_labelK_FORfor_controlloop_body
817827
{
818828
/* This runs after we've scanned the loop body*/
819829
if ($3->cmd_type == PLPGSQL_STMT_FORI)
@@ -822,7 +832,7 @@ stmt_for: opt_label K_FOR for_control loop_body
822832

823833
new = (PLpgSQL_stmt_fori *)$3;
824834
new->label =$1;
825-
new->body =$4;
835+
new->body =$4.stmts;
826836
$$ = (PLpgSQL_stmt *)new;
827837
}
828838
elseif ($3->cmd_type == PLPGSQL_STMT_FORS)
@@ -831,7 +841,7 @@ stmt_for: opt_label K_FOR for_control loop_body
831841

832842
new = (PLpgSQL_stmt_fors *)$3;
833843
new->label =$1;
834-
new->body =$4;
844+
new->body =$4.stmts;
835845
$$ = (PLpgSQL_stmt *)new;
836846
}
837847
else
@@ -841,10 +851,11 @@ stmt_for: opt_label K_FOR for_control loop_body
841851
Assert($3->cmd_type == PLPGSQL_STMT_DYNFORS);
842852
new = (PLpgSQL_stmt_dynfors *)$3;
843853
new->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*/
849860
plpgsql_ns_pop();
850861
}
@@ -1037,7 +1048,7 @@ stmt_select: K_SELECT lno
10371048
}
10381049
;
10391050

1040-
stmt_exit:exit_typelnoopt_exitlabelopt_exitcond
1051+
stmt_exit:exit_typelnoopt_labelopt_exitcond
10411052
{
10421053
PLpgSQL_stmt_exit *new;
10431054

@@ -1245,8 +1256,11 @@ raise_level: K_EXCEPTION
12451256
}
12461257
;
12471258

1248-
loop_body:proc_sectK_ENDK_LOOP';'
1249-
{$$ =$1; }
1259+
loop_body:proc_sectK_ENDK_LOOPopt_label';'
1260+
{
1261+
$$.stmts =$1;
1262+
$$.end_label =$4;
1263+
}
12501264
;
12511265

12521266
stmt_execsql:execsql_startlno
@@ -1262,7 +1276,7 @@ stmt_execsql: execsql_start lno
12621276
}
12631277
;
12641278

1265-
stmt_dynexecute :K_EXECUTElno
1279+
stmt_dynexecute :K_EXECUTElno
12661280
{
12671281
PLpgSQL_stmt_dynexecute *new;
12681282
PLpgSQL_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+
14221436
if (tok !=';')
14231437
{
14241438
plpgsql_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
{
16011615
plpgsql_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)
22102225
errposition(0);
22112226
}
22122227

2228+
staticvoid
2229+
check_labels(constchar *start_label,constchar *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"

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp