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 :
407411PLpgSQL_expr *query;
408412
409413plpgsql_ns_setlocal (false );
410- query =plpgsql_read_expression( ' ; ' , " ; " );
414+ query =read_sql_stmt( " SELECT " );
411415plpgsql_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
13081258new = malloc(sizeof (PLpgSQL_stmt_execsql));
13091259new ->cmd_type = PLPGSQL_STMT_EXECSQL;
13101260new ->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
13531303switch (tok)
13541304{
13551305case K_SELECT:
1356- new ->query =plpgsql_read_expression( ' ; ' , " ; " );
1306+ new ->query =read_sql_stmt( " SELECT " );
13571307break ;
13581308
13591309case K_EXECUTE:
1360- new ->dynquery =plpgsql_read_expression( ' ; ' , " ; " );
1310+ new ->dynquery =read_sql_stmt( " SELECT " );
13611311break ;
13621312
13631313default :
@@ -1380,7 +1330,7 @@ stmt_open: K_OPEN lno cursor_varptr
13801330elog (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{
15331491int tok;
15341492int lno;
15351493PLpgSQL_dstringds;
1494+ int parenlevel =0 ;
15361495int nparams =0 ;
15371496int params[1024 ];
15381497char buf[32 ];
15391498PLpgSQL_expr*expr;
15401499
15411500lno = yylineno;
15421501plpgsql_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+ }
15481535if (plpgsql_SpaceScanned)
15491536plpgsql_dstring_append (&ds," " );
15501537switch (tok)
15511538{
1552- case 0 :
1553- plpgsql_error_lineno = lno;
1554- elog (ERROR," missing %s at end of SQL statement" , s);
1555- break ;
1556-
15571539case T_VARIABLE:
15581540params[nparams] = yylval.var ->varno ;
15591541sprintf (buf," $%d" , ++nparams);
@@ -1618,6 +1600,8 @@ read_datatype(int tok)
16181600if (tok ==0 )
16191601{
16201602plpgsql_error_lineno = lno;
1603+ if (parenlevel !=0 )
1604+ elog (ERROR," mismatched parentheses" );
16211605elog (ERROR," incomplete datatype declaration" );
16221606}
16231607/* Possible followers for datatype in a declaration*/