4
4
* procedural language
5
5
*
6
6
* 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 $
8
8
*
9
9
* This software is copyrighted by Jan Wieck - Hamburg.
10
10
*
39
39
#include " plpgsql.h"
40
40
41
41
42
- static PLpgSQL_expr *read_sqlstmt (int until, char *s, char *sqlstart);
42
+ static PLpgSQL_expr *read_sql_construct (int until,
43
+ const char *expected,
44
+ bool isexpression,
45
+ const char *sqlstart);
46
+ static PLpgSQL_expr *read_sql_stmt (const char *sqlstart);
43
47
static PLpgSQL_type *read_datatype (int tok);
44
48
static PLpgSQL_stmt *make_select_stmt (void );
45
49
static PLpgSQL_stmt *make_fetch_stmt (void );
@@ -407,7 +411,7 @@ decl_cursor_query :
407
411
PLpgSQL_expr *query;
408
412
409
413
plpgsql_ns_setlocal (false );
410
- query = plpgsql_read_expression( ' ; ' , " ; " );
414
+ query = read_sql_stmt( " SELECT " );
411
415
plpgsql_ns_setlocal (true );
412
416
413
417
$$ = query;
@@ -1002,74 +1006,20 @@ fori_varname : T_VARIABLE
1002
1006
1003
1007
fori_lower :
1004
1008
{
1005
- int tok;
1006
- int lno;
1007
- PLpgSQL_dstring ds;
1008
- int nparams = 0 ;
1009
- int params[1024 ];
1010
- char buf[32 ];
1011
- PLpgSQL_expr *expr;
1012
- int firsttok = 1 ;
1013
-
1014
- lno = yylineno;
1015
- plpgsql_dstring_init (&ds);
1016
- plpgsql_dstring_append (&ds, " SELECT " );
1009
+ int tok;
1017
1010
1018
- $$ .reverse = 0 ;
1019
- while (( tok = yylex ()) != K_DOTDOT )
1011
+ tok = yylex () ;
1012
+ if ( tok == K_REVERSE )
1020
1013
{
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);
1062
1020
}
1063
1021
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, " .." );
1073
1023
}
1074
1024
1075
1025
stmt_fors : opt_label K_FOR lno fors_target K_IN K_SELECT expr_until_loop loop_body
@@ -1308,7 +1258,7 @@ stmt_execsql : execsql_start lno
1308
1258
new = malloc(sizeof (PLpgSQL_stmt_execsql));
1309
1259
new ->cmd_type = PLPGSQL_STMT_EXECSQL;
1310
1260
new ->lineno = $2 ;
1311
- new ->sqlstmt = read_sqlstmt( ' ; ' , " ; " , $1 );
1261
+ new ->sqlstmt = read_sql_stmt( $1 );
1312
1262
1313
1263
$$ = (PLpgSQL_stmt *)new ;
1314
1264
}
@@ -1353,11 +1303,11 @@ stmt_open : K_OPEN lno cursor_varptr
1353
1303
switch (tok)
1354
1304
{
1355
1305
case K_SELECT:
1356
- new ->query = plpgsql_read_expression( ' ; ' , " ; " );
1306
+ new ->query = read_sql_stmt( " SELECT " );
1357
1307
break ;
1358
1308
1359
1309
case K_EXECUTE:
1360
- new ->dynquery = plpgsql_read_expression( ' ; ' , " ; " );
1310
+ new ->dynquery = read_sql_stmt( " SELECT " );
1361
1311
break ;
1362
1312
1363
1313
default :
@@ -1380,7 +1330,7 @@ stmt_open : K_OPEN lno cursor_varptr
1380
1330
elog (ERROR, " cursor %s has arguments" , $3 ->refname);
1381
1331
}
1382
1332
1383
- new ->argquery = read_sqlstmt( ' ; ' , " ; " , " SELECT " );
1333
+ new ->argquery = read_sql_stmt( " SELECT " );
1384
1334
/* Remove the trailing right paren,
1385
1335
* because we want "select 1, 2", not
1386
1336
* "select (1, 2)".
@@ -1521,39 +1471,71 @@ lno :
1521
1471
1522
1472
1523
1473
PLpgSQL_expr *
1524
- plpgsql_read_expression (int until, char *s )
1474
+ plpgsql_read_expression (int until, const char *expected )
1525
1475
{
1526
- return read_sqlstmt (until, s , " SELECT " );
1476
+ return read_sql_construct (until, expected, true , " SELECT " );
1527
1477
}
1528
1478
1479
+ static PLpgSQL_expr *
1480
+ read_sql_stmt (const char *sqlstart)
1481
+ {
1482
+ return read_sql_construct (' ;' , " ;" , false , sqlstart);
1483
+ }
1529
1484
1530
1485
static PLpgSQL_expr *
1531
- read_sqlstmt (int until, char *s, char *sqlstart)
1486
+ read_sql_construct (int until,
1487
+ const char *expected,
1488
+ bool isexpression,
1489
+ const char *sqlstart)
1532
1490
{
1533
1491
int tok;
1534
1492
int lno;
1535
1493
PLpgSQL_dstring ds;
1494
+ int parenlevel = 0 ;
1536
1495
int nparams = 0 ;
1537
1496
int params[1024 ];
1538
1497
char buf[32 ];
1539
1498
PLpgSQL_expr *expr;
1540
1499
1541
1500
lno = yylineno;
1542
1501
plpgsql_dstring_init (&ds);
1543
- plpgsql_dstring_append (&ds, sqlstart);
1502
+ plpgsql_dstring_append (&ds, ( char *) sqlstart);
1544
1503
1545
- while ((tok = yylex ()) != until )
1504
+ for (;; )
1546
1505
{
1547
- if (tok == ' ;' ) break ;
1506
+ tok = yylex ();
1507
+ if (tok == ' (' )
1508
+ parenlevel++;
1509
+ else if (tok == ' )' )
1510
+ {
1511
+ parenlevel--;
1512
+ if (parenlevel < 0 )
1513
+ elog (ERROR, " mismatched parentheses" );
1514
+ }
1515
+ else if (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
+ }
1548
1535
if (plpgsql_SpaceScanned)
1549
1536
plpgsql_dstring_append (&ds, " " );
1550
1537
switch (tok)
1551
1538
{
1552
- case 0 :
1553
- plpgsql_error_lineno = lno;
1554
- elog (ERROR, " missing %s at end of SQL statement" , s);
1555
- break ;
1556
-
1557
1539
case T_VARIABLE:
1558
1540
params[nparams] = yylval.var ->varno ;
1559
1541
sprintf (buf, " $%d " , ++nparams);
@@ -1618,6 +1600,8 @@ read_datatype(int tok)
1618
1600
if (tok == 0 )
1619
1601
{
1620
1602
plpgsql_error_lineno = lno;
1603
+ if (parenlevel != 0 )
1604
+ elog (ERROR, " mismatched parentheses" );
1621
1605
elog (ERROR, " incomplete datatype declaration" );
1622
1606
}
1623
1607
/* Possible followers for datatype in a declaration */
0 commit comments