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

Commit8830ce5

Browse files
committed
Tweak plpgsql's expression reader to be smarter about parentheses and
to give more useful error messages. Stephen Szabo's example of thismorning ('loop' used as a variable name inside a subselect) workscorrectly now, and a FOR that is misinterpreted as an integer FOR willdraw 'missing .. at end of SQL expression', which is at leastmarginally helpful.
1 parentd1a2a01 commit8830ce5

File tree

2 files changed

+68
-84
lines changed

2 files changed

+68
-84
lines changed

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

Lines changed: 66 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* procedural language
55
*
66
* IDENTIFICATION
7-
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.28 2001/11/15 23:31:09 tgl Exp $
7+
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.29 2001/11/29 22:57:37 tgl Exp $
88
*
99
* This software is copyrighted by Jan Wieck - Hamburg.
1010
*
@@ -39,7 +39,11 @@
3939
#include"plpgsql.h"
4040

4141

42-
staticPLpgSQL_expr*read_sqlstmt(int until,char *s,char *sqlstart);
42+
staticPLpgSQL_expr*read_sql_construct(int until,
43+
constchar *expected,
44+
bool isexpression,
45+
constchar *sqlstart);
46+
staticPLpgSQL_expr*read_sql_stmt(constchar *sqlstart);
4347
staticPLpgSQL_type*read_datatype(int tok);
4448
staticPLpgSQL_stmt*make_select_stmt(void);
4549
staticPLpgSQL_stmt*make_fetch_stmt(void);
@@ -407,7 +411,7 @@ decl_cursor_query :
407411
PLpgSQL_expr *query;
408412

409413
plpgsql_ns_setlocal(false);
410-
query =plpgsql_read_expression(';',";");
414+
query =read_sql_stmt("SELECT");
411415
plpgsql_ns_setlocal(true);
412416

413417
$$ = query;
@@ -1002,74 +1006,20 @@ fori_varname: T_VARIABLE
10021006

10031007
fori_lower:
10041008
{
1005-
inttok;
1006-
intlno;
1007-
PLpgSQL_dstring ds;
1008-
intnparams =0;
1009-
intparams[1024];
1010-
charbuf[32];
1011-
PLpgSQL_expr*expr;
1012-
intfirsttok =1;
1013-
1014-
lno = yylineno;
1015-
plpgsql_dstring_init(&ds);
1016-
plpgsql_dstring_append(&ds,"SELECT");
1009+
inttok;
10171010

1018-
$$.reverse =0;
1019-
while((tok =yylex()) != K_DOTDOT)
1011+
tok =yylex();
1012+
if (tok == K_REVERSE)
10201013
{
1021-
if (firsttok)
1022-
{
1023-
firsttok =0;
1024-
if (tok == K_REVERSE)
1025-
{
1026-
$$.reverse =1;
1027-
continue;
1028-
}
1029-
}
1030-
if (tok ==';')break;
1031-
if (plpgsql_SpaceScanned)
1032-
plpgsql_dstring_append(&ds,"");
1033-
switch (tok)
1034-
{
1035-
case T_VARIABLE:
1036-
params[nparams] = yylval.var->varno;
1037-
sprintf(buf," $%d", ++nparams);
1038-
plpgsql_dstring_append(&ds, buf);
1039-
break;
1040-
1041-
case T_RECFIELD:
1042-
params[nparams] = yylval.recfield->rfno;
1043-
sprintf(buf," $%d", ++nparams);
1044-
plpgsql_dstring_append(&ds, buf);
1045-
break;
1046-
1047-
case T_TGARGV:
1048-
params[nparams] = yylval.trigarg->dno;
1049-
sprintf(buf," $%d", ++nparams);
1050-
plpgsql_dstring_append(&ds, buf);
1051-
break;
1052-
1053-
default:
1054-
if (tok ==0)
1055-
{
1056-
plpgsql_error_lineno = lno;
1057-
elog(ERROR,"missing .. to terminate lower bound of for loop");
1058-
}
1059-
plpgsql_dstring_append(&ds, yytext);
1060-
break;
1061-
}
1014+
$$.reverse =1;
1015+
}
1016+
else
1017+
{
1018+
$$.reverse =0;
1019+
plpgsql_push_back_token(tok);
10621020
}
10631021

1064-
expr = malloc(sizeof(PLpgSQL_expr) +sizeof(int) * nparams -sizeof(int));
1065-
expr->dtype= PLPGSQL_DTYPE_EXPR;
1066-
expr->query= strdup(plpgsql_dstring_get(&ds));
1067-
expr->plan=NULL;
1068-
expr->nparams= nparams;
1069-
while(nparams-- >0)
1070-
expr->params[nparams] = params[nparams];
1071-
plpgsql_dstring_free(&ds);
1072-
$$.expr = expr;
1022+
$$.expr = plpgsql_read_expression(K_DOTDOT,"..");
10731023
}
10741024

10751025
stmt_fors:opt_labelK_FORlnofors_targetK_INK_SELECTexpr_until_looploop_body
@@ -1308,7 +1258,7 @@ stmt_execsql: execsql_start lno
13081258
new = malloc(sizeof(PLpgSQL_stmt_execsql));
13091259
new->cmd_type = PLPGSQL_STMT_EXECSQL;
13101260
new->lineno =$2;
1311-
new->sqlstmt =read_sqlstmt(';',";",$1);
1261+
new->sqlstmt =read_sql_stmt($1);
13121262

13131263
$$ = (PLpgSQL_stmt *)new;
13141264
}
@@ -1353,11 +1303,11 @@ stmt_open: K_OPEN lno cursor_varptr
13531303
switch (tok)
13541304
{
13551305
case K_SELECT:
1356-
new->query =plpgsql_read_expression(';',";");
1306+
new->query =read_sql_stmt("SELECT");
13571307
break;
13581308

13591309
case K_EXECUTE:
1360-
new->dynquery =plpgsql_read_expression(';',";");
1310+
new->dynquery =read_sql_stmt("SELECT");
13611311
break;
13621312

13631313
default:
@@ -1380,7 +1330,7 @@ stmt_open: K_OPEN lno cursor_varptr
13801330
elog(ERROR,"cursor %s has arguments", $3->refname);
13811331
}
13821332

1383-
new->argquery =read_sqlstmt(';',";","SELECT");
1333+
new->argquery =read_sql_stmt("SELECT");
13841334
/* Remove the trailing right paren,
13851335
* because we want "select 1, 2", not
13861336
* "select (1, 2)".
@@ -1521,39 +1471,71 @@ lno:
15211471

15221472

15231473
PLpgSQL_expr *
1524-
plpgsql_read_expression(int until,char *s)
1474+
plpgsql_read_expression(int until,constchar *expected)
15251475
{
1526-
returnread_sqlstmt(until,s,"SELECT");
1476+
returnread_sql_construct(until,expected,true,"SELECT");
15271477
}
15281478

1479+
static PLpgSQL_expr *
1480+
read_sql_stmt(constchar *sqlstart)
1481+
{
1482+
returnread_sql_construct(';',";",false, sqlstart);
1483+
}
15291484

15301485
static PLpgSQL_expr *
1531-
read_sqlstmt (int until,char *s,char *sqlstart)
1486+
read_sql_construct(int until,
1487+
constchar *expected,
1488+
bool isexpression,
1489+
constchar *sqlstart)
15321490
{
15331491
inttok;
15341492
intlno;
15351493
PLpgSQL_dstringds;
1494+
intparenlevel =0;
15361495
intnparams =0;
15371496
intparams[1024];
15381497
charbuf[32];
15391498
PLpgSQL_expr*expr;
15401499

15411500
lno = yylineno;
15421501
plpgsql_dstring_init(&ds);
1543-
plpgsql_dstring_append(&ds, sqlstart);
1502+
plpgsql_dstring_append(&ds,(char *)sqlstart);
15441503

1545-
while((tok =yylex()) != until)
1504+
for (;;)
15461505
{
1547-
if (tok ==';')break;
1506+
tok =yylex();
1507+
if (tok =='(')
1508+
parenlevel++;
1509+
elseif (tok ==')')
1510+
{
1511+
parenlevel--;
1512+
if (parenlevel <0)
1513+
elog(ERROR,"mismatched parentheses");
1514+
}
1515+
elseif (parenlevel ==0 && tok == until)
1516+
break;
1517+
/*
1518+
* End of function definition is an error, and we don't expect to
1519+
* hit a semicolon either (unless it's the until symbol, in which
1520+
* case we should have fallen out above).
1521+
*/
1522+
if (tok ==0 || tok ==';')
1523+
{
1524+
plpgsql_error_lineno = lno;
1525+
if (parenlevel !=0)
1526+
elog(ERROR,"mismatched parentheses");
1527+
if (isexpression)
1528+
elog(ERROR,"missing %s at end of SQL expression",
1529+
expected);
1530+
else
1531+
elog(ERROR,"missing %s at end of SQL statement",
1532+
expected);
1533+
break;
1534+
}
15481535
if (plpgsql_SpaceScanned)
15491536
plpgsql_dstring_append(&ds,"");
15501537
switch (tok)
15511538
{
1552-
case0:
1553-
plpgsql_error_lineno = lno;
1554-
elog(ERROR,"missing %s at end of SQL statement", s);
1555-
break;
1556-
15571539
case T_VARIABLE:
15581540
params[nparams] = yylval.var->varno;
15591541
sprintf(buf," $%d", ++nparams);
@@ -1618,6 +1600,8 @@ read_datatype(int tok)
16181600
if (tok ==0)
16191601
{
16201602
plpgsql_error_lineno = lno;
1603+
if (parenlevel !=0)
1604+
elog(ERROR,"mismatched parentheses");
16211605
elog(ERROR,"incomplete datatype declaration");
16221606
}
16231607
/* Possible followers for datatype in a declaration*/

‎src/pl/plpgsql/src/plpgsql.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.23 2001/11/15 23:31:09 tgl Exp $
6+
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.24 2001/11/29 22:57:37 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -606,7 +606,7 @@ extern void plpgsql_dumptree(PLpgSQL_function * func);
606606
* Externs in gram.y and scan.l
607607
* ----------
608608
*/
609-
externPLpgSQL_expr*plpgsql_read_expression(intuntil,char*s);
609+
externPLpgSQL_expr*plpgsql_read_expression(intuntil,constchar*expected);
610610
externintplpgsql_yyparse(void);
611611
externintplpgsql_base_yylex(void);
612612
externintplpgsql_yylex(void);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp