9
9
*
10
10
*
11
11
* 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 $
13
13
*
14
14
*-------------------------------------------------------------------------
15
15
*/
21
21
22
22
static PLpgSQL_expr *read_sql_construct (int until,
23
23
int until2,
24
+ int until3,
24
25
const char *expected,
25
26
const char *sqlstart,
26
27
bool isexpression,
27
28
bool valid_sql,
28
29
int *endtoken);
30
+ static PLpgSQL_expr *read_sql_expression2 (int until, int until2,
31
+ const char *expected,
32
+ int *endtoken);
29
33
static PLpgSQL_expr *read_sql_stmt (const char *sqlstart);
30
34
static PLpgSQL_type *read_datatype (int tok);
31
35
static PLpgSQL_stmt *make_execsql_stmt (const char *sqlstart, int lineno);
@@ -200,6 +204,7 @@ static void check_labels(const char *start_label,
200
204
%token K_THEN
201
205
%token K_TO
202
206
%token K_TYPE
207
+ %token K_USING
203
208
%token K_WARNING
204
209
%token K_WHEN
205
210
%token K_WHILE
@@ -892,8 +897,11 @@ for_control :
892
897
{
893
898
PLpgSQL_stmt_dynfors *new ;
894
899
PLpgSQL_expr *expr;
900
+ int term;
895
901
896
- expr = plpgsql_read_expression(K_LOOP, " LOOP" );
902
+ expr = read_sql_expression2(K_LOOP, K_USING,
903
+ " LOOP or USING" ,
904
+ &term);
897
905
898
906
new = palloc0(sizeof (PLpgSQL_stmt_dynfors));
899
907
new ->cmd_type = PLPGSQL_STMT_DYNFORS;
@@ -921,6 +929,17 @@ for_control :
921
929
}
922
930
new ->query = expr;
923
931
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
+
924
943
$$ = (PLpgSQL_stmt *) new ;
925
944
}
926
945
else
@@ -954,6 +973,7 @@ for_control :
954
973
*/
955
974
expr1 = read_sql_construct(K_DOTDOT,
956
975
K_LOOP,
976
+ 0 ,
957
977
" LOOP" ,
958
978
" SELECT " ,
959
979
true ,
@@ -973,17 +993,14 @@ for_control :
973
993
check_sql_expr (expr1->query);
974
994
975
995
/* 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);
983
999
984
1000
/* Get the BY clause if any */
985
1001
if (tok == K_BY)
986
- expr_by = plpgsql_read_expression(K_LOOP, " LOOP" );
1002
+ expr_by = plpgsql_read_expression(K_LOOP,
1003
+ " LOOP" );
987
1004
else
988
1005
expr_by = NULL ;
989
1006
@@ -1217,18 +1234,15 @@ stmt_raise : K_RAISE lno raise_level raise_msg
1217
1234
1218
1235
if (tok == ' ,' )
1219
1236
{
1220
- PLpgSQL_expr *expr;
1221
- int term;
1222
-
1223
- for (;;)
1237
+ do
1224
1238
{
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);
1228
1244
new ->params = lappend(new ->params, expr);
1229
- if (term == ' ;' )
1230
- break ;
1231
- }
1245
+ } while (tok == ' ,' );
1232
1246
}
1233
1247
1234
1248
$$ = (PLpgSQL_stmt *)new ;
@@ -1307,7 +1321,8 @@ stmt_dynexecute : K_EXECUTE lno
1307
1321
PLpgSQL_expr *expr;
1308
1322
int endtoken;
1309
1323
1310
- expr = read_sql_construct(K_INTO, ' ;' , " INTO|;" ,
1324
+ expr = read_sql_construct(K_INTO, K_USING, ' ;' ,
1325
+ " INTO or USING or ;" ,
1311
1326
" SELECT " ,
1312
1327
true , true , &endtoken);
1313
1328
@@ -1319,16 +1334,30 @@ stmt_dynexecute : K_EXECUTE lno
1319
1334
new ->strict = false ;
1320
1335
new ->rec = NULL ;
1321
1336
new ->row = NULL ;
1337
+ new ->params = NIL;
1322
1338
1323
1339
/* If we found "INTO", collect the argument */
1324
1340
if (endtoken == K_INTO)
1325
1341
{
1326
1342
new ->into = true ;
1327
1343
read_into_target (&new ->rec, &new ->row, &new ->strict);
1328
- if (yylex () != ' ;' )
1344
+ endtoken = yylex ();
1345
+ if (endtoken != ' ;' && endtoken != K_USING)
1329
1346
yyerror (" syntax error" );
1330
1347
}
1331
1348
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
+
1332
1361
$$ = (PLpgSQL_stmt *)new ;
1333
1362
}
1334
1363
;
@@ -1485,7 +1514,7 @@ stmt_fetch : K_FETCH lno opt_fetch_direction cursor_variable K_INTO
1485
1514
$$ = (PLpgSQL_stmt *)fetch;
1486
1515
}
1487
1516
;
1488
-
1517
+
1489
1518
stmt_move : K_MOVE lno opt_fetch_direction cursor_variable ' ;'
1490
1519
{
1491
1520
PLpgSQL_stmt_fetch *fetch = $3 ;
@@ -1730,33 +1759,48 @@ assign_expr_param(int dno, int *params, int *nparams)
1730
1759
}
1731
1760
1732
1761
1762
+ /* Convenience routine to read an expression with one possible terminator */
1733
1763
PLpgSQL_expr *
1734
1764
plpgsql_read_expression (int until, const char *expected)
1735
1765
{
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 );
1737
1768
}
1738
1769
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 ';' */
1739
1780
static PLpgSQL_expr *
1740
1781
read_sql_stmt (const char *sqlstart)
1741
1782
{
1742
- return read_sql_construct (' ;' , 0 , " ;" , sqlstart, false , true , NULL );
1783
+ return read_sql_construct (' ;' , 0 , 0 , " ;" ,
1784
+ sqlstart, false , true , NULL );
1743
1785
}
1744
1786
1745
1787
/*
1746
1788
* Read a SQL construct and build a PLpgSQL_expr for it.
1747
1789
*
1748
1790
* until: token code for expected terminator
1749
1791
* until2: token code for alternate terminator (pass 0 if none)
1792
+ * until3: token code for another alternate terminator (pass 0 if none)
1750
1793
* expected: text to use in complaining that terminator was not found
1751
1794
* sqlstart: text to prefix to the accumulated SQL text
1752
1795
* isexpression: whether to say we're reading an "expression" or a "statement"
1753
1796
* valid_sql: whether to check the syntax of the expr (prefixed with sqlstart)
1754
1797
* 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)
1756
1799
*/
1757
1800
static PLpgSQL_expr *
1758
1801
read_sql_construct (int until,
1759
1802
int until2,
1803
+ int until3,
1760
1804
const char *expected,
1761
1805
const char *sqlstart,
1762
1806
bool isexpression,
@@ -1783,6 +1827,8 @@ read_sql_construct(int until,
1783
1827
break ;
1784
1828
if (tok == until2 && parenlevel == 0 )
1785
1829
break ;
1830
+ if (tok == until3 && parenlevel == 0 )
1831
+ break ;
1786
1832
if (tok == ' (' || tok == ' [' )
1787
1833
parenlevel++;
1788
1834
else if (tok == ' )' || tok == ' ]' )
@@ -2066,15 +2112,17 @@ read_fetch_direction(void)
2066
2112
else if (pg_strcasecmp (yytext, " absolute" ) == 0 )
2067
2113
{
2068
2114
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 );
2071
2118
check_FROM = false ;
2072
2119
}
2073
2120
else if (pg_strcasecmp (yytext, " relative" ) == 0 )
2074
2121
{
2075
2122
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 );
2078
2126
check_FROM = false ;
2079
2127
}
2080
2128
else if (pg_strcasecmp (yytext, " forward" ) == 0 )
@@ -2088,8 +2136,9 @@ read_fetch_direction(void)
2088
2136
else if (tok != T_SCALAR)
2089
2137
{
2090
2138
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 );
2093
2142
check_FROM = false ;
2094
2143
}
2095
2144
else
@@ -2233,7 +2282,7 @@ make_return_query_stmt(int lineno)
2233
2282
new = palloc0 (sizeof (PLpgSQL_stmt_return_query));
2234
2283
new ->cmd_type = PLPGSQL_STMT_RETURN_QUERY;
2235
2284
new ->lineno = lineno;
2236
- new ->query = read_sql_construct ( ' ; ' , 0 , " ) " , " " , false , true , NULL );
2285
+ new ->query = read_sql_stmt ( " " );
2237
2286
2238
2287
return (PLpgSQL_stmt *) new ;
2239
2288
}
0 commit comments