99 *
1010 *
1111 * IDENTIFICATION
12- * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.108 2008/01 /0119:46:00 momjian Exp $
12+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.109 2008/04 /0103:51:09 tgl Exp $
1313 *
1414 *-------------------------------------------------------------------------
1515*/
2121
2222static PLpgSQL_expr*read_sql_construct (int until,
2323int until2,
24+ int until3,
2425const char *expected,
2526const char *sqlstart,
2627bool isexpression,
2728bool valid_sql,
2829int *endtoken);
30+ static PLpgSQL_expr*read_sql_expression2 (int until,int until2,
31+ const char *expected,
32+ int *endtoken);
2933static PLpgSQL_expr*read_sql_stmt (const char *sqlstart);
3034static PLpgSQL_type*read_datatype (int tok);
3135static PLpgSQL_stmt*make_execsql_stmt (const char *sqlstart,int lineno);
@@ -200,6 +204,7 @@ staticvoid check_labels(const char *start_label,
200204%token K_THEN
201205%token K_TO
202206%token K_TYPE
207+ %token K_USING
203208%token K_WARNING
204209%token K_WHEN
205210%token K_WHILE
@@ -892,8 +897,11 @@ for_control:
892897{
893898PLpgSQL_stmt_dynfors*new ;
894899PLpgSQL_expr*expr;
900+ int term;
895901
896- expr = plpgsql_read_expression(K_LOOP," LOOP" );
902+ expr = read_sql_expression2(K_LOOP, K_USING,
903+ " LOOP or USING" ,
904+ &term);
897905
898906new = palloc0(sizeof (PLpgSQL_stmt_dynfors));
899907new ->cmd_type = PLPGSQL_STMT_DYNFORS;
@@ -921,6 +929,17 @@ for_control:
921929}
922930new ->query = expr;
923931
932+ if (term == K_USING)
933+ {
934+ do
935+ {
936+ expr = read_sql_expression2(' ,' , K_LOOP,
937+ " , or LOOP" ,
938+ &term);
939+ new ->params = lappend(new ->params, expr);
940+ }while (term ==' ,' );
941+ }
942+
924943$$ = (PLpgSQL_stmt *)new ;
925944}
926945else
@@ -954,6 +973,7 @@ for_control:
954973*/
955974expr1 = read_sql_construct(K_DOTDOT,
956975 K_LOOP,
976+ 0 ,
957977" LOOP" ,
958978" SELECT" ,
959979true ,
@@ -973,17 +993,14 @@ for_control:
973993check_sql_expr (expr1->query);
974994
975995/* Read and check the second one*/
976- expr2 = read_sql_construct(K_LOOP,
977- K_BY,
978- " LOOP" ,
979- " SELECT" ,
980- true ,
981- true ,
982- &tok);
996+ expr2 = read_sql_expression2(K_LOOP, K_BY,
997+ " LOOP" ,
998+ &tok);
983999
9841000/* Get the BY clause if any*/
9851001if (tok == K_BY)
986- expr_by = plpgsql_read_expression(K_LOOP," LOOP" );
1002+ expr_by = plpgsql_read_expression(K_LOOP,
1003+ " LOOP" );
9871004else
9881005expr_by =NULL ;
9891006
@@ -1217,18 +1234,15 @@ stmt_raise: K_RAISE lno raise_level raise_msg
12171234
12181235if (tok ==' ,' )
12191236{
1220- PLpgSQL_expr *expr;
1221- int term;
1222-
1223- for (;;)
1237+ do
12241238{
1225- expr = read_sql_construct(' ,' ,' ;' ," , or ;" ,
1226- " SELECT" ,
1227- true ,true , &term);
1239+ PLpgSQL_expr *expr;
1240+
1241+ expr = read_sql_expression2(' ,' ,' ;' ,
1242+ " , or ;" ,
1243+ &tok);
12281244new ->params = lappend(new ->params, expr);
1229- if (term ==' ;' )
1230- break ;
1231- }
1245+ }while (tok ==' ,' );
12321246}
12331247
12341248$$ = (PLpgSQL_stmt *)new ;
@@ -1307,7 +1321,8 @@ stmt_dynexecute : K_EXECUTE lno
13071321PLpgSQL_expr *expr;
13081322int endtoken;
13091323
1310- expr = read_sql_construct(K_INTO,' ;' ," INTO|;" ,
1324+ expr = read_sql_construct(K_INTO, K_USING,' ;' ,
1325+ " INTO or USING or ;" ,
13111326" SELECT" ,
13121327true ,true , &endtoken);
13131328
@@ -1319,16 +1334,30 @@ stmt_dynexecute : K_EXECUTE lno
13191334new ->strict =false ;
13201335new ->rec =NULL ;
13211336new ->row =NULL ;
1337+ new ->params = NIL;
13221338
13231339/* If we found "INTO", collect the argument*/
13241340if (endtoken == K_INTO)
13251341{
13261342new ->into =true ;
13271343read_into_target (&new ->rec, &new ->row, &new ->strict);
1328- if (yylex () !=' ;' )
1344+ endtoken =yylex ();
1345+ if (endtoken !=' ;' && endtoken != K_USING)
13291346yyerror (" syntax error" );
13301347}
13311348
1349+ /* If we found "USING", collect the argument(s)*/
1350+ if (endtoken == K_USING)
1351+ {
1352+ do
1353+ {
1354+ expr = read_sql_expression2(' ,' ,' ;' ,
1355+ " , or ;" ,
1356+ &endtoken);
1357+ new ->params = lappend(new ->params, expr);
1358+ }while (endtoken ==' ,' );
1359+ }
1360+
13321361$$ = (PLpgSQL_stmt *)new ;
13331362}
13341363;
@@ -1485,7 +1514,7 @@ stmt_fetch: K_FETCH lno opt_fetch_direction cursor_variable K_INTO
14851514$$ = (PLpgSQL_stmt *)fetch;
14861515}
14871516;
1488-
1517+
14891518stmt_move :K_MOVE lno opt_fetch_direction cursor_variable ' ;'
14901519{
14911520PLpgSQL_stmt_fetch *fetch =$3 ;
@@ -1730,33 +1759,48 @@ assign_expr_param(int dno, int *params, int *nparams)
17301759}
17311760
17321761
1762+ /* Convenience routine to read an expression with one possible terminator*/
17331763PLpgSQL_expr *
17341764plpgsql_read_expression (int until,const char *expected)
17351765{
1736- return read_sql_construct (until,0 , expected," SELECT" ,true ,true ,NULL );
1766+ return read_sql_construct (until,0 ,0 , expected,
1767+ " SELECT" ,true ,true ,NULL );
17371768}
17381769
1770+ /* Convenience routine to read an expression with two possible terminators*/
1771+ static PLpgSQL_expr *
1772+ read_sql_expression2 (int until,int until2,const char *expected,
1773+ int *endtoken)
1774+ {
1775+ return read_sql_construct (until, until2,0 , expected,
1776+ " SELECT" ,true ,true , endtoken);
1777+ }
1778+
1779+ /* Convenience routine to read a SQL statement that must end with ';'*/
17391780static PLpgSQL_expr *
17401781read_sql_stmt (const char *sqlstart)
17411782{
1742- return read_sql_construct (' ;' ,0 ," ;" , sqlstart,false ,true ,NULL );
1783+ return read_sql_construct (' ;' ,0 ,0 ," ;" ,
1784+ sqlstart,false ,true ,NULL );
17431785}
17441786
17451787/*
17461788 * Read a SQL construct and build a PLpgSQL_expr for it.
17471789 *
17481790 * until:token code for expected terminator
17491791 * until2:token code for alternate terminator (pass 0 if none)
1792+ * until3:token code for another alternate terminator (pass 0 if none)
17501793 * expected:text to use in complaining that terminator was not found
17511794 * sqlstart:text to prefix to the accumulated SQL text
17521795 * isexpression: whether to say we're reading an "expression" or a "statement"
17531796 * valid_sql: whether to check the syntax of the expr (prefixed with sqlstart)
17541797 * endtoken:if not NULL, ending token is stored at *endtoken
1755- *(this is only interesting if until2 isn't zero)
1798+ *(this is only interesting if until2or until3 isn't zero)
17561799*/
17571800static PLpgSQL_expr *
17581801read_sql_construct (int until,
17591802int until2,
1803+ int until3,
17601804const char *expected,
17611805const char *sqlstart,
17621806bool isexpression,
@@ -1783,6 +1827,8 @@ read_sql_construct(int until,
17831827break ;
17841828if (tok == until2 && parenlevel ==0 )
17851829break ;
1830+ if (tok == until3 && parenlevel ==0 )
1831+ break ;
17861832if (tok ==' (' || tok ==' [' )
17871833parenlevel++;
17881834else if (tok ==' )' || tok ==' ]' )
@@ -2066,15 +2112,17 @@ read_fetch_direction(void)
20662112else if (pg_strcasecmp (yytext," absolute" ) ==0 )
20672113{
20682114fetch->direction = FETCH_ABSOLUTE;
2069- fetch->expr =read_sql_construct (K_FROM, K_IN," FROM or IN" ,
2070- " SELECT" ,true ,true ,NULL );
2115+ fetch->expr =read_sql_expression2 (K_FROM, K_IN,
2116+ " FROM or IN" ,
2117+ NULL );
20712118check_FROM =false ;
20722119}
20732120else if (pg_strcasecmp (yytext," relative" ) ==0 )
20742121{
20752122fetch->direction = FETCH_RELATIVE;
2076- fetch->expr =read_sql_construct (K_FROM, K_IN," FROM or IN" ,
2077- " SELECT" ,true ,true ,NULL );
2123+ fetch->expr =read_sql_expression2 (K_FROM, K_IN,
2124+ " FROM or IN" ,
2125+ NULL );
20782126check_FROM =false ;
20792127}
20802128else if (pg_strcasecmp (yytext," forward" ) ==0 )
@@ -2088,8 +2136,9 @@ read_fetch_direction(void)
20882136else if (tok != T_SCALAR)
20892137{
20902138plpgsql_push_back_token (tok);
2091- fetch->expr =read_sql_construct (K_FROM, K_IN," FROM or IN" ,
2092- " SELECT" ,true ,true ,NULL );
2139+ fetch->expr =read_sql_expression2 (K_FROM, K_IN,
2140+ " FROM or IN" ,
2141+ NULL );
20932142check_FROM =false ;
20942143}
20952144else
@@ -2233,7 +2282,7 @@ make_return_query_stmt(int lineno)
22332282new =palloc0 (sizeof (PLpgSQL_stmt_return_query));
22342283new ->cmd_type = PLPGSQL_STMT_RETURN_QUERY;
22352284new ->lineno = lineno;
2236- new ->query =read_sql_construct ( ' ; ' , 0 , " ) " , " " , false , true , NULL );
2285+ new ->query =read_sql_stmt ( " " );
22372286
22382287return (PLpgSQL_stmt *)new ;
22392288}