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 *
3939#include " plpgsql.h"
4040
4141
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);
4347static PLpgSQL_type *read_datatype (int tok);
4448static PLpgSQL_stmt *make_select_stmt (void );
4549static PLpgSQL_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
10031007fori_lower :
10041008 {
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;
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
10751025stmt_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
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
15231473PLpgSQL_expr *
1524- plpgsql_read_expression (int until, char *s )
1474+ plpgsql_read_expression (int until, const char *expected )
15251475{
1526- return read_sqlstmt (until, s , " SELECT " );
1476+ return read_sql_construct (until, expected, true , " SELECT " );
15271477}
15281478
1479+ static PLpgSQL_expr *
1480+ read_sql_stmt (const char *sqlstart)
1481+ {
1482+ return read_sql_construct (' ;' , " ;" , false , sqlstart);
1483+ }
15291484
15301485static 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)
15321490{
15331491 int tok;
15341492 int lno;
15351493 PLpgSQL_dstring ds;
1494+ int parenlevel = 0 ;
15361495 int nparams = 0 ;
15371496 int params[1024 ];
15381497 char buf[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+ 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+ }
15481535 if (plpgsql_SpaceScanned)
15491536 plpgsql_dstring_append (&ds, " " );
15501537 switch (tok)
15511538 {
1552- case 0 :
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 */
0 commit comments