2009/9/28 John Naylor <jcnay...@gmail.com>: > Pavel, > > It looks good. My last email didn't go to -hackers, since I wasn't > subscribed. I had to resend to -hackers so there will be a link for > the commitfest page. I think you might have to resend your latest > patch to the list. Sorry!
nothing, patch attached Pavel > > In any case, I will say it's ready for commiter. > > Thanks, > John > > On Mon, Sep 28, 2009 at 2:07 AM, Pavel Stehule <pavel.steh...@gmail.com> > wrote: >> Hello >> >> I am sending actualised patch as per John comment. >> >> regards >> Pavel Stehule >> >> 2009/9/26 John Naylor <jcnay...@gmail.com>: >>> Hi, >>> >>> Sorry, I didn't notice the attachment on Pavel's email, otherwise I >>> would have done this sooner! :) >>> >>> I just applied and tested the new patch. Everything works great. >>> >>> The only thing I would change now is some of the comments. >>> >>> 1). On line 289, one of the regression test comments got copied: >>> >>> + move forward in c; --should be at '5' >>> >>> change to: >>> >>> + move forward in c; --should be at '1' >>> >>> 2). Lines 79/80: >>> >>> + >>> errmsg("statement FETCH returns more rows."), >>> + >>> errhint("Multirows fetch are not allowed in PL/pgSQL."))); >>> >>> This might sound better as "statement FETCH returns multiple rows.", >>> and "Multirow FETCH is not allowed in PL/pgSQL." >>> >>> Everything else looks good to me. >>> John >>> >>> >>>> Hi Selena and John, >>>> >>>> Pavel's latest patch seems to address all the issues you raised in >>>> your initial review. Do you have any comments on this new revision? >>>> If you're happy that your issues have been resolved, please mark the >>>> patch as Ready for Committer. >>>> >>>> Cheers, >>>> BJ >>>> >>> >> >
*** ./doc/src/sgml/plpgsql.sgml.orig 2009-09-28 09:38:55.711469112 +0200 --- ./doc/src/sgml/plpgsql.sgml 2009-09-28 09:39:24.613468923 +0200 *************** *** 2656,2670 **** <para> The options for the <replaceable>direction</replaceable> clause are ! the same as for <command>FETCH</>, namely <literal>NEXT</>, <literal>PRIOR</>, <literal>FIRST</>, <literal>LAST</>, <literal>ABSOLUTE</> <replaceable>count</replaceable>, <literal>RELATIVE</> <replaceable>count</replaceable>, ! <literal>FORWARD</>, or ! <literal>BACKWARD</>. Omitting <replaceable>direction</replaceable> is the same as specifying <literal>NEXT</>. <replaceable>direction</replaceable> values that require moving --- 2656,2670 ---- <para> The options for the <replaceable>direction</replaceable> clause are ! similar to <command>FETCH</>, namely <literal>NEXT</>, <literal>PRIOR</>, <literal>FIRST</>, <literal>LAST</>, <literal>ABSOLUTE</> <replaceable>count</replaceable>, <literal>RELATIVE</> <replaceable>count</replaceable>, ! <literal>FORWARD</> <optional> <replaceable>count</replaceable> | <literal>ALL</> </optional>, or ! <literal>BACKWARD</> <optional> <replaceable>count</replaceable> | <literal>ALL</> </optional>. Omitting <replaceable>direction</replaceable> is the same as specifying <literal>NEXT</>. <replaceable>direction</replaceable> values that require moving *************** *** 2678,2683 **** --- 2678,2684 ---- MOVE curs1; MOVE LAST FROM curs3; MOVE RELATIVE -2 FROM curs4; + MOVE FORWARD 2 FROM curs4; </programlisting> </para> </sect3> *** ./src/pl/plpgsql/src/gram.y.orig 2009-09-28 09:38:55.713470217 +0200 --- ./src/pl/plpgsql/src/gram.y 2009-09-28 11:00:53.811467762 +0200 *************** *** 72,77 **** --- 72,79 ---- int until, const char *expected); static List *read_raise_options(void); + static PLpgSQL_stmt_fetch *complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM); + %} %expect 0 *************** *** 178,183 **** --- 180,186 ---- * Keyword tokens */ %token K_ALIAS + %token K_ALL %token K_ASSIGN %token K_BEGIN %token K_BY *************** *** 1621,1626 **** --- 1624,1635 ---- if (yylex() != ';') yyerror("syntax error"); + + if (fetch->returns_multiple_rows) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("statement FETCH returns multiple rows"), + errhint("Multirow FETCH is not allowed in PL/pgSQL."))); fetch->lineno = $2; fetch->rec = rec; *************** *** 2252,2257 **** --- 2261,2271 ---- } + /* + * Read FETCH or MOVE statement direction. By default, + * cursor will only move one row. To MOVE more than one row + * at a time see complete_direction(). + */ static PLpgSQL_stmt_fetch * read_fetch_direction(void) { *************** *** 2269,2274 **** --- 2283,2289 ---- fetch->direction = FETCH_FORWARD; fetch->how_many = 1; fetch->expr = NULL; + fetch->returns_multiple_rows = false; /* * Most of the direction keywords are not plpgsql keywords, so we *************** *** 2313,2323 **** } else if (pg_strcasecmp(yytext, "forward") == 0) { ! /* use defaults */ } else if (pg_strcasecmp(yytext, "backward") == 0) { fetch->direction = FETCH_BACKWARD; } else if (tok != T_SCALAR) { --- 2328,2339 ---- } else if (pg_strcasecmp(yytext, "forward") == 0) { ! fetch = complete_direction(fetch, &check_FROM); } else if (pg_strcasecmp(yytext, "backward") == 0) { fetch->direction = FETCH_BACKWARD; + fetch = complete_direction(fetch, &check_FROM); } else if (tok != T_SCALAR) { *************** *** 2346,2351 **** --- 2362,2415 ---- } + /* + * Allows directions: + * FORWARD expr, FORWARD ALL, FORWARD + * BACKWARD expr, BACKWARD ALL, BACKWARD + * + * so plpgsql should fully support PostgreSQL's MOVE statement. + */ + static PLpgSQL_stmt_fetch * + complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM) + { + int tok; + + tok = yylex(); + if (tok == K_FROM || tok == K_IN) + { + *check_FROM = false; + + return fetch; + } + + if (tok == K_ALL) + { + fetch->how_many = fetch->direction == FETCH_FORWARD ? -1 : 0; + fetch->direction = FETCH_ABSOLUTE; + fetch->returns_multiple_rows = true; + *check_FROM = true; + + return fetch; + } + + plpgsql_push_back_token(tok); + fetch->expr = read_sql_expression2(K_FROM, K_IN, + "FROM or IN", + NULL); + + /* + * We don't allow multiple rows in PL/pgSQL's FETCH statement. This + * limit is enforced by syntax. Only for sure one row directions + * are allowed. Because result of expr should be greather than + * one, we expect possible multiple rows and disable this direction + * when current statement is FETCH statement. + */ + fetch->returns_multiple_rows = true; + *check_FROM = false; + + return fetch; + } + static PLpgSQL_stmt * make_return_stmt(int lineno) { *** ./src/pl/plpgsql/src/plpgsql.h.orig 2009-09-28 09:38:55.715469366 +0200 --- ./src/pl/plpgsql/src/plpgsql.h 2009-09-28 09:39:24.653469785 +0200 *************** *** 520,525 **** --- 520,526 ---- int how_many; /* count, if constant (expr is NULL) */ PLpgSQL_expr *expr; /* count, if expression */ bool is_move; /* is this a fetch or move? */ + bool returns_multiple_rows; /* returns more than one rows? */ } PLpgSQL_stmt_fetch; *** ./src/test/regress/expected/plpgsql.out.orig 2009-09-28 09:38:55.719468503 +0200 --- ./src/test/regress/expected/plpgsql.out 2009-09-28 09:39:24.684468331 +0200 *************** *** 3027,3032 **** --- 3027,3054 ---- create or replace function sc_test() returns setof integer as $$ declare + c refcursor; + x integer; + begin + open c scroll for execute 'select f1 from int4_tbl'; + fetch last from c into x; + while found loop + return next x; + move backward 2 from c; + fetch relative -1 from c into x; + end loop; + close c; + end; + $$ language plpgsql; + select * from sc_test(); + sc_test + ------------- + -2147483647 + 123456 + (2 rows) + + create or replace function sc_test() returns setof integer as $$ + declare c cursor for select * from generate_series(1, 10); x integer; begin *************** *** 3052,3057 **** --- 3074,3149 ---- 9 (3 rows) + create or replace function sc_test() returns setof integer as $$ + declare + c cursor for select * from generate_series(1, 10); + x integer; + begin + open c; + loop + move forward 2 in c; + if not found then + exit; + end if; + fetch next from c into x; + if found then + return next x; + end if; + end loop; + close c; + end; + $$ language plpgsql; + select * from sc_test(); + sc_test + --------- + 3 + 6 + 9 + (3 rows) + + drop function sc_test(); + create or replace function sc_test() returns integer + as $$ + declare + c cursor for select * from generate_series(1, 10); + x integer; + begin + open c; + move forward in c; --should be at '5' + fetch relative 0 from c into x; --fetch current position + if found then + return x; + end if; + close c; + end; + $$ language plpgsql; + select sc_test(); + sc_test + --------- + 1 + (1 row) + + create or replace function sc_test() returns integer + as $$ + declare + c cursor for select * from generate_series(1, 10); + x integer; + begin + open c; + move forward 5 in c; --should be at '5' + fetch relative 0 from c into x; --fetch current position + if found then + return x; + end if; + close c; + end; + $$ language plpgsql; + select sc_test(); + sc_test + --------- + 5 + (1 row) + drop function sc_test(); -- test qualified variable names create function pl_qual_names (param1 int) returns void as $$ *** ./src/test/regress/sql/plpgsql.sql.orig 2009-09-28 09:38:55.721469049 +0200 --- ./src/test/regress/sql/plpgsql.sql 2009-09-28 10:58:39.991468013 +0200 *************** *** 2513,2518 **** --- 2513,2536 ---- create or replace function sc_test() returns setof integer as $$ declare + c refcursor; + x integer; + begin + open c scroll for execute 'select f1 from int4_tbl'; + fetch last from c into x; + while found loop + return next x; + move backward 2 from c; + fetch relative -1 from c into x; + end loop; + close c; + end; + $$ language plpgsql; + + select * from sc_test(); + + create or replace function sc_test() returns setof integer as $$ + declare c cursor for select * from generate_series(1, 10); x integer; begin *************** *** 2533,2540 **** --- 2551,2619 ---- select * from sc_test(); + create or replace function sc_test() returns setof integer as $$ + declare + c cursor for select * from generate_series(1, 10); + x integer; + begin + open c; + loop + move forward 2 in c; + if not found then + exit; + end if; + fetch next from c into x; + if found then + return next x; + end if; + end loop; + close c; + end; + $$ language plpgsql; + + select * from sc_test(); + + drop function sc_test(); + + create or replace function sc_test() returns integer + as $$ + declare + c cursor for select * from generate_series(1, 10); + x integer; + begin + open c; + move forward in c; --should be at '1' + fetch relative 0 from c into x; --fetch current position + if found then + return x; + end if; + close c; + end; + $$ language plpgsql; + + select sc_test(); + + create or replace function sc_test() returns integer + as $$ + declare + c cursor for select * from generate_series(1, 10); + x integer; + begin + open c; + move forward 5 in c; --should be at '5' + fetch relative 0 from c into x; --fetch current position + if found then + return x; + end if; + close c; + end; + $$ language plpgsql; + + select sc_test(); + drop function sc_test(); + -- test qualified variable names create function pl_qual_names (param1 int) returns void as $$
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers