99 *
1010 *
1111 * IDENTIFICATION
12- * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.108 2008/01 /01 19:46:00 momjian Exp $
12+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.109 2008/04 /01 03:51:09 tgl Exp $
1313 *
1414 *-------------------------------------------------------------------------
1515 */
2121
2222static PLpgSQL_expr *read_sql_construct (int until,
2323 int until2,
24+ int until3,
2425 const char *expected,
2526 const char *sqlstart,
2627 bool isexpression,
2728 bool valid_sql,
2829 int *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 @@ static void 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 {
893898 PLpgSQL_stmt_dynfors *new ;
894899 PLpgSQL_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
898906 new = palloc0(sizeof (PLpgSQL_stmt_dynfors));
899907 new ->cmd_type = PLPGSQL_STMT_DYNFORS;
@@ -921,6 +929,17 @@ for_control :
921929 }
922930 new ->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 }
926945 else
@@ -954,6 +973,7 @@ for_control :
954973 */
955974 expr1 = read_sql_construct(K_DOTDOT,
956975 K_LOOP,
976+ 0 ,
957977 " LOOP" ,
958978 " SELECT " ,
959979 true ,
@@ -973,17 +993,14 @@ for_control :
973993 check_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 */
9851001 if (tok == K_BY)
986- expr_by = plpgsql_read_expression(K_LOOP, " LOOP" );
1002+ expr_by = plpgsql_read_expression(K_LOOP,
1003+ " LOOP" );
9871004 else
9881005 expr_by = NULL ;
9891006
@@ -1217,18 +1234,15 @@ stmt_raise : K_RAISE lno raise_level raise_msg
12171234
12181235 if (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);
12281244 new ->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
13071321 PLpgSQL_expr *expr;
13081322 int 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 " ,
13121327 true , true , &endtoken);
13131328
@@ -1319,16 +1334,30 @@ stmt_dynexecute : K_EXECUTE lno
13191334 new ->strict = false ;
13201335 new ->rec = NULL ;
13211336 new ->row = NULL ;
1337+ new ->params = NIL;
13221338
13231339 /* If we found "INTO", collect the argument */
13241340 if (endtoken == K_INTO)
13251341 {
13261342 new ->into = true ;
13271343 read_into_target (&new ->rec, &new ->row, &new ->strict);
1328- if (yylex () != ' ;' )
1344+ endtoken = yylex ();
1345+ if (endtoken != ' ;' && endtoken != K_USING)
13291346 yyerror (" 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 {
14911520 PLpgSQL_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 until2 or until3 isn't zero)
17561799 */
17571800static PLpgSQL_expr *
17581801read_sql_construct (int until,
17591802 int until2,
1803+ int until3,
17601804 const char *expected,
17611805 const char *sqlstart,
17621806 bool isexpression,
@@ -1783,6 +1827,8 @@ read_sql_construct(int until,
17831827 break ;
17841828 if (tok == until2 && parenlevel == 0 )
17851829 break ;
1830+ if (tok == until3 && parenlevel == 0 )
1831+ break ;
17861832 if (tok == ' (' || tok == ' [' )
17871833 parenlevel++;
17881834 else if (tok == ' )' || tok == ' ]' )
@@ -2066,15 +2112,17 @@ read_fetch_direction(void)
20662112 else if (pg_strcasecmp (yytext, " absolute" ) == 0 )
20672113 {
20682114 fetch->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 );
20712118 check_FROM = false ;
20722119 }
20732120 else if (pg_strcasecmp (yytext, " relative" ) == 0 )
20742121 {
20752122 fetch->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 );
20782126 check_FROM = false ;
20792127 }
20802128 else if (pg_strcasecmp (yytext, " forward" ) == 0 )
@@ -2088,8 +2136,9 @@ read_fetch_direction(void)
20882136 else if (tok != T_SCALAR)
20892137 {
20902138 plpgsql_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 );
20932142 check_FROM = false ;
20942143 }
20952144 else
@@ -2233,7 +2282,7 @@ make_return_query_stmt(int lineno)
22332282 new = palloc0 (sizeof (PLpgSQL_stmt_return_query));
22342283 new ->cmd_type = PLPGSQL_STMT_RETURN_QUERY;
22352284 new ->lineno = lineno;
2236- new ->query = read_sql_construct ( ' ; ' , 0 , " ) " , " " , false , true , NULL );
2285+ new ->query = read_sql_stmt ( " " );
22372286
22382287 return (PLpgSQL_stmt *) new ;
22392288}
0 commit comments