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

Commit3648147

Browse files
committed
Get rid of "lookahead" functionality in plpgsql's yylex() function,
and instead make the grammar production for the RETURN statement do theheavy lifting. The lookahead idea was copied from the main parser, butit does not work in plpgsql's parser because here gram.y looks explicitlyat the scanner's yytext variable, which will be out of sync after afailed lookahead step. A minimal example iscreate or replace function foo() returns void language plpgsql as 'begin perform return foo bar;end';which can be seen by testing to deliver "foo foo bar" to the main parserinstead of the expected "return foo bar". This isn't a huge bug sinceRETURN is not found in the main grammar, but it could bite someone whotried to use "return" as an identifier.Back-patch to 8.1. Bug exists further back, but HEAD patch doesn't applycleanly, and given the lack of field complaints it doesn't seem worththe effort to develop adjusted patches.
1 parent1b67e0c commit3648147

File tree

2 files changed

+142
-158
lines changed

2 files changed

+142
-158
lines changed

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

Lines changed: 134 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.93 2006/06/16 23:29:26 tgl Exp $
12+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.94 2006/08/14 00:46:53 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -28,8 +28,10 @@ static PLpgSQL_expr*read_sql_construct(int until,
2828
int *endtoken);
2929
staticPLpgSQL_expr*read_sql_stmt(constchar *sqlstart);
3030
staticPLpgSQL_type*read_datatype(int tok);
31-
staticPLpgSQL_stmt*make_select_stmt(void);
32-
staticPLpgSQL_stmt*make_fetch_stmt(void);
31+
staticPLpgSQL_stmt*make_select_stmt(int lineno);
32+
staticPLpgSQL_stmt*make_fetch_stmt(int lineno,int curvar);
33+
staticPLpgSQL_stmt*make_return_stmt(int lineno);
34+
staticPLpgSQL_stmt*make_return_next_stmt(int lineno);
3335
staticvoidcheck_assignable(PLpgSQL_datum *datum);
3436
staticPLpgSQL_row*read_into_scalar_list(constchar *initial_name,
3537
PLpgSQL_datum *initial_datum);
@@ -118,7 +120,7 @@ staticvoid check_labels(const char *start_label,
118120
%type<loop_body>loop_body
119121
%type<stmt>proc_stmtpl_block
120122
%type<stmt>stmt_assignstmt_ifstmt_loopstmt_whilestmt_exit
121-
%type<stmt>stmt_returnstmt_return_nextstmt_raisestmt_execsql
123+
%type<stmt>stmt_returnstmt_raisestmt_execsql
122124
%type<stmt>stmt_forstmt_selectstmt_perform
123125
%type<stmt>stmt_dynexecutestmt_getdiag
124126
%type<stmt>stmt_openstmt_fetchstmt_closestmt_null
@@ -183,7 +185,6 @@ staticvoid check_labels(const char *start_label,
183185
%tokenK_RENAME
184186
%tokenK_RESULT_OID
185187
%tokenK_RETURN
186-
%tokenK_RETURN_NEXT
187188
%tokenK_REVERSE
188189
%tokenK_SELECT
189190
%tokenK_STRICT
@@ -596,8 +597,6 @@ proc_stmt: pl_block ';'
596597
{$$ =$1; }
597598
|stmt_return
598599
{$$ =$1; }
599-
|stmt_return_next
600-
{$$ =$1; }
601600
|stmt_raise
602601
{$$ =$1; }
603602
|stmt_execsql
@@ -1130,8 +1129,7 @@ for_variable: T_SCALAR
11301129

11311130
stmt_select:K_SELECTlno
11321131
{
1133-
$$ = make_select_stmt();
1134-
$$->lineno =$2;
1132+
$$ = make_select_stmt($2);
11351133
}
11361134
;
11371135

@@ -1162,109 +1160,18 @@ exit_type: K_EXIT
11621160

11631161
stmt_return:K_RETURNlno
11641162
{
1165-
PLpgSQL_stmt_return *new;
1166-
1167-
new = palloc0(sizeof(PLpgSQL_stmt_return));
1168-
new->cmd_type = PLPGSQL_STMT_RETURN;
1169-
new->lineno =$2;
1170-
new->expr =NULL;
1171-
new->retvarno = -1;
1163+
inttok;
11721164

1173-
if (plpgsql_curr_compile->fn_retset)
1174-
{
1175-
if (yylex() !=';')
1176-
yyerror("RETURN cannot have a parameter in function returning set; use RETURN NEXT");
1177-
}
1178-
elseif (plpgsql_curr_compile->out_param_varno >=0)
1179-
{
1180-
if (yylex() !=';')
1181-
yyerror("RETURN cannot have a parameter in function with OUT parameters");
1182-
new->retvarno = plpgsql_curr_compile->out_param_varno;
1183-
}
1184-
elseif (plpgsql_curr_compile->fn_rettype == VOIDOID)
1165+
tok =yylex();
1166+
if (tok == K_NEXT)
11851167
{
1186-
if (yylex() !=';')
1187-
yyerror("RETURN cannot have a parameter in function returning void");
1188-
}
1189-
elseif (plpgsql_curr_compile->fn_retistuple)
1190-
{
1191-
switch (yylex())
1192-
{
1193-
case K_NULL:
1194-
/* we allow this to support RETURN NULL in triggers*/
1195-
break;
1196-
1197-
case T_ROW:
1198-
new->retvarno = yylval.row->rowno;
1199-
break;
1200-
1201-
case T_RECORD:
1202-
new->retvarno = yylval.rec->recno;
1203-
break;
1204-
1205-
default:
1206-
yyerror("RETURN must specify a record or row variable in function returning tuple");
1207-
break;
1208-
}
1209-
if (yylex() !=';')
1210-
yyerror("RETURN must specify a record or row variable in function returning tuple");
1168+
$$ = make_return_next_stmt($2);
12111169
}
12121170
else
12131171
{
1214-
/*
1215-
* Note that a well-formed expression is
1216-
* _required_ here; anything else is a
1217-
* compile-time error.
1218-
*/
1219-
new->expr = plpgsql_read_expression(';',";");
1172+
plpgsql_push_back_token(tok);
1173+
$$ = make_return_stmt($2);
12201174
}
1221-
1222-
$$ = (PLpgSQL_stmt *)new;
1223-
}
1224-
;
1225-
1226-
stmt_return_next:K_RETURN_NEXTlno
1227-
{
1228-
PLpgSQL_stmt_return_next *new;
1229-
1230-
if (!plpgsql_curr_compile->fn_retset)
1231-
yyerror("cannot use RETURN NEXT in a non-SETOF function");
1232-
1233-
new = palloc0(sizeof(PLpgSQL_stmt_return_next));
1234-
new->cmd_type= PLPGSQL_STMT_RETURN_NEXT;
1235-
new->lineno=$2;
1236-
new->expr =NULL;
1237-
new->retvarno= -1;
1238-
1239-
if (plpgsql_curr_compile->out_param_varno >=0)
1240-
{
1241-
if (yylex() !=';')
1242-
yyerror("RETURN NEXT cannot have a parameter in function with OUT parameters");
1243-
new->retvarno = plpgsql_curr_compile->out_param_varno;
1244-
}
1245-
elseif (plpgsql_curr_compile->fn_retistuple)
1246-
{
1247-
switch (yylex())
1248-
{
1249-
case T_ROW:
1250-
new->retvarno = yylval.row->rowno;
1251-
break;
1252-
1253-
case T_RECORD:
1254-
new->retvarno = yylval.rec->recno;
1255-
break;
1256-
1257-
default:
1258-
yyerror("RETURN NEXT must specify a record or row variable in function returning tuple");
1259-
break;
1260-
}
1261-
if (yylex() !=';')
1262-
yyerror("RETURN NEXT must specify a record or row variable in function returning tuple");
1263-
}
1264-
else
1265-
new->expr = plpgsql_read_expression(';',";");
1266-
1267-
$$ = (PLpgSQL_stmt *)new;
12681175
}
12691176
;
12701177

@@ -1537,13 +1444,7 @@ stmt_open: K_OPEN lno cursor_varptr
15371444

15381445
stmt_fetch:K_FETCHlnocursor_variableK_INTO
15391446
{
1540-
PLpgSQL_stmt_fetch *new;
1541-
1542-
new = (PLpgSQL_stmt_fetch *)make_fetch_stmt();
1543-
new->curvar =$3;
1544-
1545-
$$ = (PLpgSQL_stmt *)new;
1546-
$$->lineno =$2;
1447+
$$ = make_fetch_stmt($2,$3);
15471448
}
15481449
;
15491450

@@ -1991,7 +1892,7 @@ read_datatype(int tok)
19911892
}
19921893

19931894
static PLpgSQL_stmt *
1994-
make_select_stmt(void)
1895+
make_select_stmt(int lineno)
19951896
{
19961897
PLpgSQL_dstringds;
19971898
intnparams =0;
@@ -2112,6 +2013,7 @@ make_select_stmt(void)
21122013

21132014
select =palloc0(sizeof(PLpgSQL_stmt_select));
21142015
select->cmd_type = PLPGSQL_STMT_SELECT;
2016+
select->lineno = lineno;
21152017
select->rec = rec;
21162018
select->row = row;
21172019
select->query = expr;
@@ -2125,6 +2027,7 @@ make_select_stmt(void)
21252027

21262028
execsql =palloc(sizeof(PLpgSQL_stmt_execsql));
21272029
execsql->cmd_type = PLPGSQL_STMT_EXECSQL;
2030+
execsql->lineno = lineno;
21282031
execsql->sqlstmt = expr;
21292032

21302033
return (PLpgSQL_stmt *)execsql;
@@ -2133,7 +2036,7 @@ make_select_stmt(void)
21332036

21342037

21352038
static PLpgSQL_stmt *
2136-
make_fetch_stmt(void)
2039+
make_fetch_stmt(int lineno,int curvar)
21372040
{
21382041
inttok;
21392042
PLpgSQL_row *row =NULL;
@@ -2172,12 +2075,124 @@ make_fetch_stmt(void)
21722075
if (tok !=';')
21732076
yyerror("syntax error");
21742077

2175-
fetch =palloc0(sizeof(PLpgSQL_stmt_select));
2078+
fetch =palloc0(sizeof(PLpgSQL_stmt_fetch));
21762079
fetch->cmd_type = PLPGSQL_STMT_FETCH;
2177-
fetch->rec = rec;
2178-
fetch->row = row;
2080+
fetch->lineno= lineno;
2081+
fetch->rec= rec;
2082+
fetch->row= row;
2083+
fetch->curvar= curvar;
2084+
2085+
return (PLpgSQL_stmt *) fetch;
2086+
}
2087+
2088+
2089+
static PLpgSQL_stmt *
2090+
make_return_stmt(int lineno)
2091+
{
2092+
PLpgSQL_stmt_return *new;
2093+
2094+
new =palloc0(sizeof(PLpgSQL_stmt_return));
2095+
new->cmd_type = PLPGSQL_STMT_RETURN;
2096+
new->lineno = lineno;
2097+
new->expr =NULL;
2098+
new->retvarno = -1;
2099+
2100+
if (plpgsql_curr_compile->fn_retset)
2101+
{
2102+
if (yylex() !=';')
2103+
yyerror("RETURN cannot have a parameter in function returning set; use RETURN NEXT");
2104+
}
2105+
elseif (plpgsql_curr_compile->out_param_varno >=0)
2106+
{
2107+
if (yylex() !=';')
2108+
yyerror("RETURN cannot have a parameter in function with OUT parameters");
2109+
new->retvarno = plpgsql_curr_compile->out_param_varno;
2110+
}
2111+
elseif (plpgsql_curr_compile->fn_rettype == VOIDOID)
2112+
{
2113+
if (yylex() !=';')
2114+
yyerror("RETURN cannot have a parameter in function returning void");
2115+
}
2116+
elseif (plpgsql_curr_compile->fn_retistuple)
2117+
{
2118+
switch (yylex())
2119+
{
2120+
case K_NULL:
2121+
/* we allow this to support RETURN NULL in triggers*/
2122+
break;
2123+
2124+
case T_ROW:
2125+
new->retvarno = yylval.row->rowno;
2126+
break;
2127+
2128+
case T_RECORD:
2129+
new->retvarno = yylval.rec->recno;
2130+
break;
2131+
2132+
default:
2133+
yyerror("RETURN must specify a record or row variable in function returning tuple");
2134+
break;
2135+
}
2136+
if (yylex() !=';')
2137+
yyerror("RETURN must specify a record or row variable in function returning tuple");
2138+
}
2139+
else
2140+
{
2141+
/*
2142+
* Note that a well-formed expression is
2143+
* _required_ here; anything else is a
2144+
* compile-time error.
2145+
*/
2146+
new->expr =plpgsql_read_expression(';',";");
2147+
}
2148+
2149+
return (PLpgSQL_stmt *)new;
2150+
}
2151+
2152+
2153+
static PLpgSQL_stmt *
2154+
make_return_next_stmt(int lineno)
2155+
{
2156+
PLpgSQL_stmt_return_next *new;
2157+
2158+
if (!plpgsql_curr_compile->fn_retset)
2159+
yyerror("cannot use RETURN NEXT in a non-SETOF function");
2160+
2161+
new =palloc0(sizeof(PLpgSQL_stmt_return_next));
2162+
new->cmd_type= PLPGSQL_STMT_RETURN_NEXT;
2163+
new->lineno= lineno;
2164+
new->expr=NULL;
2165+
new->retvarno= -1;
2166+
2167+
if (plpgsql_curr_compile->out_param_varno >=0)
2168+
{
2169+
if (yylex() !=';')
2170+
yyerror("RETURN NEXT cannot have a parameter in function with OUT parameters");
2171+
new->retvarno = plpgsql_curr_compile->out_param_varno;
2172+
}
2173+
elseif (plpgsql_curr_compile->fn_retistuple)
2174+
{
2175+
switch (yylex())
2176+
{
2177+
case T_ROW:
2178+
new->retvarno = yylval.row->rowno;
2179+
break;
2180+
2181+
case T_RECORD:
2182+
new->retvarno = yylval.rec->recno;
2183+
break;
2184+
2185+
default:
2186+
yyerror("RETURN NEXT must specify a record or row variable in function returning tuple");
2187+
break;
2188+
}
2189+
if (yylex() !=';')
2190+
yyerror("RETURN NEXT must specify a record or row variable in function returning tuple");
2191+
}
2192+
else
2193+
new->expr =plpgsql_read_expression(';',";");
21792194

2180-
return (PLpgSQL_stmt *)fetch;
2195+
return (PLpgSQL_stmt *)new;
21812196
}
21822197

21832198

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp