mirror of
https://github.com/postgres/postgres.git
synced 2025-07-26 01:22:12 +03:00
Allow MOVE FORWARD n, MOVE BACKWARD n, MOVE FORWARD ALL, MOVE BACKWARD ALL
in plpgsql. Clean up a couple of corner cases in the MOVE/FETCH syntax. Pavel Stehule
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.142 2009/06/18 10:22:08 petere Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.143 2009/09/29 20:05:29 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="plpgsql">
|
<chapter id="plpgsql">
|
||||||
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
|
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
|
||||||
@ -2655,16 +2655,18 @@ MOVE <optional> <replaceable>direction</replaceable> { FROM | IN } </optional> <
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The options for the <replaceable>direction</replaceable> clause are
|
The <replaceable>direction</replaceable> clause can be any of the
|
||||||
the same as for <command>FETCH</>, namely
|
variants allowed in the SQL <xref linkend="sql-fetch"
|
||||||
|
endterm="sql-fetch-title"> command, namely
|
||||||
<literal>NEXT</>,
|
<literal>NEXT</>,
|
||||||
<literal>PRIOR</>,
|
<literal>PRIOR</>,
|
||||||
<literal>FIRST</>,
|
<literal>FIRST</>,
|
||||||
<literal>LAST</>,
|
<literal>LAST</>,
|
||||||
<literal>ABSOLUTE</> <replaceable>count</replaceable>,
|
<literal>ABSOLUTE</> <replaceable>count</replaceable>,
|
||||||
<literal>RELATIVE</> <replaceable>count</replaceable>,
|
<literal>RELATIVE</> <replaceable>count</replaceable>,
|
||||||
<literal>FORWARD</>, or
|
<literal>ALL</>,
|
||||||
<literal>BACKWARD</>.
|
<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
|
Omitting <replaceable>direction</replaceable> is the same
|
||||||
as specifying <literal>NEXT</>.
|
as specifying <literal>NEXT</>.
|
||||||
<replaceable>direction</replaceable> values that require moving
|
<replaceable>direction</replaceable> values that require moving
|
||||||
@ -2678,6 +2680,7 @@ MOVE <optional> <replaceable>direction</replaceable> { FROM | IN } </optional> <
|
|||||||
MOVE curs1;
|
MOVE curs1;
|
||||||
MOVE LAST FROM curs3;
|
MOVE LAST FROM curs3;
|
||||||
MOVE RELATIVE -2 FROM curs4;
|
MOVE RELATIVE -2 FROM curs4;
|
||||||
|
MOVE FORWARD 2 FROM curs4;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</sect3>
|
</sect3>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.127 2009/07/22 02:31:38 joe Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.128 2009/09/29 20:05:29 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -48,6 +48,8 @@ static PLpgSQL_expr *read_sql_stmt(const char *sqlstart);
|
|||||||
static PLpgSQL_type *read_datatype(int tok);
|
static PLpgSQL_type *read_datatype(int tok);
|
||||||
static PLpgSQL_stmt *make_execsql_stmt(const char *sqlstart, int lineno);
|
static PLpgSQL_stmt *make_execsql_stmt(const char *sqlstart, int lineno);
|
||||||
static PLpgSQL_stmt_fetch *read_fetch_direction(void);
|
static PLpgSQL_stmt_fetch *read_fetch_direction(void);
|
||||||
|
static void complete_direction(PLpgSQL_stmt_fetch *fetch,
|
||||||
|
bool *check_FROM);
|
||||||
static PLpgSQL_stmt *make_return_stmt(int lineno);
|
static PLpgSQL_stmt *make_return_stmt(int lineno);
|
||||||
static PLpgSQL_stmt *make_return_next_stmt(int lineno);
|
static PLpgSQL_stmt *make_return_next_stmt(int lineno);
|
||||||
static PLpgSQL_stmt *make_return_query_stmt(int lineno);
|
static PLpgSQL_stmt *make_return_query_stmt(int lineno);
|
||||||
@ -178,6 +180,7 @@ static List *read_raise_options(void);
|
|||||||
* Keyword tokens
|
* Keyword tokens
|
||||||
*/
|
*/
|
||||||
%token K_ALIAS
|
%token K_ALIAS
|
||||||
|
%token K_ALL
|
||||||
%token K_ASSIGN
|
%token K_ASSIGN
|
||||||
%token K_BEGIN
|
%token K_BEGIN
|
||||||
%token K_BY
|
%token K_BY
|
||||||
@ -1622,6 +1625,15 @@ stmt_fetch : K_FETCH lno opt_fetch_direction cursor_variable K_INTO
|
|||||||
if (yylex() != ';')
|
if (yylex() != ';')
|
||||||
yyerror("syntax error");
|
yyerror("syntax error");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't allow multiple rows in PL/pgSQL's FETCH
|
||||||
|
* statement, only in MOVE.
|
||||||
|
*/
|
||||||
|
if (fetch->returns_multiple_rows)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("FETCH statement cannot return multiple rows")));
|
||||||
|
|
||||||
fetch->lineno = $2;
|
fetch->lineno = $2;
|
||||||
fetch->rec = rec;
|
fetch->rec = rec;
|
||||||
fetch->row = row;
|
fetch->row = row;
|
||||||
@ -2252,6 +2264,9 @@ make_execsql_stmt(const char *sqlstart, int lineno)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read FETCH or MOVE direction clause (everything through FROM/IN).
|
||||||
|
*/
|
||||||
static PLpgSQL_stmt_fetch *
|
static PLpgSQL_stmt_fetch *
|
||||||
read_fetch_direction(void)
|
read_fetch_direction(void)
|
||||||
{
|
{
|
||||||
@ -2269,6 +2284,7 @@ read_fetch_direction(void)
|
|||||||
fetch->direction = FETCH_FORWARD;
|
fetch->direction = FETCH_FORWARD;
|
||||||
fetch->how_many = 1;
|
fetch->how_many = 1;
|
||||||
fetch->expr = NULL;
|
fetch->expr = NULL;
|
||||||
|
fetch->returns_multiple_rows = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Most of the direction keywords are not plpgsql keywords, so we
|
* Most of the direction keywords are not plpgsql keywords, so we
|
||||||
@ -2311,26 +2327,46 @@ read_fetch_direction(void)
|
|||||||
NULL);
|
NULL);
|
||||||
check_FROM = false;
|
check_FROM = false;
|
||||||
}
|
}
|
||||||
|
else if (pg_strcasecmp(yytext, "all") == 0)
|
||||||
|
{
|
||||||
|
fetch->how_many = FETCH_ALL;
|
||||||
|
fetch->returns_multiple_rows = true;
|
||||||
|
}
|
||||||
else if (pg_strcasecmp(yytext, "forward") == 0)
|
else if (pg_strcasecmp(yytext, "forward") == 0)
|
||||||
{
|
{
|
||||||
/* use defaults */
|
complete_direction(fetch, &check_FROM);
|
||||||
}
|
}
|
||||||
else if (pg_strcasecmp(yytext, "backward") == 0)
|
else if (pg_strcasecmp(yytext, "backward") == 0)
|
||||||
{
|
{
|
||||||
fetch->direction = FETCH_BACKWARD;
|
fetch->direction = FETCH_BACKWARD;
|
||||||
|
complete_direction(fetch, &check_FROM);
|
||||||
}
|
}
|
||||||
else if (tok != T_SCALAR)
|
else if (tok == K_FROM || tok == K_IN)
|
||||||
{
|
{
|
||||||
|
/* empty direction */
|
||||||
|
check_FROM = false;
|
||||||
|
}
|
||||||
|
else if (tok == T_SCALAR)
|
||||||
|
{
|
||||||
|
/* Assume there's no direction clause and tok is a cursor name */
|
||||||
plpgsql_push_back_token(tok);
|
plpgsql_push_back_token(tok);
|
||||||
fetch->expr = read_sql_expression2(K_FROM, K_IN,
|
|
||||||
"FROM or IN",
|
|
||||||
NULL);
|
|
||||||
check_FROM = false;
|
check_FROM = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Assume there's no direction clause */
|
/*
|
||||||
|
* Assume it's a count expression with no preceding keyword.
|
||||||
|
* Note: we allow this syntax because core SQL does, but we don't
|
||||||
|
* document it because of the ambiguity with the omitted-direction
|
||||||
|
* case. For instance, "MOVE n IN c" will fail if n is a scalar.
|
||||||
|
* Perhaps this can be improved someday, but it's hardly worth a
|
||||||
|
* lot of work.
|
||||||
|
*/
|
||||||
plpgsql_push_back_token(tok);
|
plpgsql_push_back_token(tok);
|
||||||
|
fetch->expr = read_sql_expression2(K_FROM, K_IN,
|
||||||
|
"FROM or IN",
|
||||||
|
NULL);
|
||||||
|
fetch->returns_multiple_rows = true;
|
||||||
check_FROM = false;
|
check_FROM = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2345,6 +2381,43 @@ read_fetch_direction(void)
|
|||||||
return fetch;
|
return fetch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process remainder of FETCH/MOVE direction after FORWARD or BACKWARD.
|
||||||
|
* Allows these cases:
|
||||||
|
* FORWARD expr, FORWARD ALL, FORWARD
|
||||||
|
* BACKWARD expr, BACKWARD ALL, BACKWARD
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM)
|
||||||
|
{
|
||||||
|
int tok;
|
||||||
|
|
||||||
|
tok = yylex();
|
||||||
|
if (tok == 0)
|
||||||
|
yyerror("unexpected end of function definition");
|
||||||
|
|
||||||
|
if (tok == K_FROM || tok == K_IN)
|
||||||
|
{
|
||||||
|
*check_FROM = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tok == K_ALL)
|
||||||
|
{
|
||||||
|
fetch->how_many = FETCH_ALL;
|
||||||
|
fetch->returns_multiple_rows = true;
|
||||||
|
*check_FROM = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
plpgsql_push_back_token(tok);
|
||||||
|
fetch->expr = read_sql_expression2(K_FROM, K_IN,
|
||||||
|
"FROM or IN",
|
||||||
|
NULL);
|
||||||
|
fetch->returns_multiple_rows = true;
|
||||||
|
*check_FROM = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PLpgSQL_stmt *
|
static PLpgSQL_stmt *
|
||||||
make_return_stmt(int lineno)
|
make_return_stmt(int lineno)
|
||||||
@ -3043,11 +3116,11 @@ make_case(int lineno, PLpgSQL_expr *t_expr,
|
|||||||
|
|
||||||
/* copy expression query without SELECT keyword (expr->query + 7) */
|
/* copy expression query without SELECT keyword (expr->query + 7) */
|
||||||
Assert(strncmp(expr->query, "SELECT ", 7) == 0);
|
Assert(strncmp(expr->query, "SELECT ", 7) == 0);
|
||||||
|
|
||||||
/* And do the string hacking */
|
/* And do the string hacking */
|
||||||
initStringInfo(&ds);
|
initStringInfo(&ds);
|
||||||
|
|
||||||
appendStringInfo(&ds, "SELECT $%d IN(%s)",
|
appendStringInfo(&ds, "SELECT $%d IN(%s)",
|
||||||
nparams + 1,
|
nparams + 1,
|
||||||
expr->query + 7);
|
expr->query + 7);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.80 2009/07/22 02:31:38 joe Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.81 2009/09/29 20:05:29 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -854,7 +854,7 @@ dump_cursor_direction(PLpgSQL_stmt_fetch *stmt)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printf("%d\n", stmt->how_many);
|
printf("%ld\n", stmt->how_many);
|
||||||
|
|
||||||
dump_indent -= 2;
|
dump_indent -= 2;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.116 2009/09/22 23:43:42 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.117 2009/09/29 20:05:29 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -517,9 +517,10 @@ typedef struct
|
|||||||
PLpgSQL_row *row;
|
PLpgSQL_row *row;
|
||||||
int curvar; /* cursor variable to fetch from */
|
int curvar; /* cursor variable to fetch from */
|
||||||
FetchDirection direction; /* fetch direction */
|
FetchDirection direction; /* fetch direction */
|
||||||
int how_many; /* count, if constant (expr is NULL) */
|
long how_many; /* count, if constant (expr is NULL) */
|
||||||
PLpgSQL_expr *expr; /* count, if expression */
|
PLpgSQL_expr *expr; /* count, if expression */
|
||||||
bool is_move; /* is this a fetch or move? */
|
bool is_move; /* is this a fetch or move? */
|
||||||
|
bool returns_multiple_rows; /* can return more than one row? */
|
||||||
} PLpgSQL_stmt_fetch;
|
} PLpgSQL_stmt_fetch;
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.71 2009/07/13 00:42:18 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.72 2009/09/29 20:05:29 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -147,6 +147,7 @@ param \${digit}+
|
|||||||
= { return K_ASSIGN; }
|
= { return K_ASSIGN; }
|
||||||
\.\. { return K_DOTDOT; }
|
\.\. { return K_DOTDOT; }
|
||||||
alias { return K_ALIAS; }
|
alias { return K_ALIAS; }
|
||||||
|
all { return K_ALL; }
|
||||||
begin { return K_BEGIN; }
|
begin { return K_BEGIN; }
|
||||||
by { return K_BY; }
|
by { return K_BY; }
|
||||||
case { return K_CASE; }
|
case { return K_CASE; }
|
||||||
|
@ -3025,6 +3025,28 @@ select * from sc_test();
|
|||||||
0
|
0
|
||||||
(3 rows)
|
(3 rows)
|
||||||
|
|
||||||
|
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 $$
|
create or replace function sc_test() returns setof integer as $$
|
||||||
declare
|
declare
|
||||||
c cursor for select * from generate_series(1, 10);
|
c cursor for select * from generate_series(1, 10);
|
||||||
@ -3052,6 +3074,26 @@ select * from sc_test();
|
|||||||
9
|
9
|
||||||
(3 rows)
|
(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;
|
||||||
|
move forward all in c;
|
||||||
|
fetch backward from c into x;
|
||||||
|
if found then
|
||||||
|
return next x;
|
||||||
|
end if;
|
||||||
|
close c;
|
||||||
|
end;
|
||||||
|
$$ language plpgsql;
|
||||||
|
select * from sc_test();
|
||||||
|
sc_test
|
||||||
|
---------
|
||||||
|
10
|
||||||
|
(1 row)
|
||||||
|
|
||||||
drop function sc_test();
|
drop function sc_test();
|
||||||
-- test qualified variable names
|
-- test qualified variable names
|
||||||
create function pl_qual_names (param1 int) returns void as $$
|
create function pl_qual_names (param1 int) returns void as $$
|
||||||
@ -3864,7 +3906,7 @@ drop function strtest();
|
|||||||
-- Test anonymous code blocks.
|
-- Test anonymous code blocks.
|
||||||
DO $$
|
DO $$
|
||||||
DECLARE r record;
|
DECLARE r record;
|
||||||
BEGIN
|
BEGIN
|
||||||
FOR r IN SELECT rtrim(roomno) AS roomno, comment FROM Room ORDER BY roomno
|
FOR r IN SELECT rtrim(roomno) AS roomno, comment FROM Room ORDER BY roomno
|
||||||
LOOP
|
LOOP
|
||||||
RAISE NOTICE '%, %', r.roomno, r.comment;
|
RAISE NOTICE '%, %', r.roomno, r.comment;
|
||||||
@ -3887,7 +3929,7 @@ LINE 1: DO LANGUAGE plpgsql $$begin return 1; end$$;
|
|||||||
^
|
^
|
||||||
DO LANGUAGE plpgsql $$
|
DO LANGUAGE plpgsql $$
|
||||||
DECLARE r record;
|
DECLARE r record;
|
||||||
BEGIN
|
BEGIN
|
||||||
FOR r IN SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY roomno
|
FOR r IN SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY roomno
|
||||||
LOOP
|
LOOP
|
||||||
RAISE NOTICE '%, %', r.roomno, r.comment;
|
RAISE NOTICE '%, %', r.roomno, r.comment;
|
||||||
|
@ -2511,6 +2511,24 @@ $$ language plpgsql;
|
|||||||
|
|
||||||
select * from sc_test();
|
select * from sc_test();
|
||||||
|
|
||||||
|
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 $$
|
create or replace function sc_test() returns setof integer as $$
|
||||||
declare
|
declare
|
||||||
c cursor for select * from generate_series(1, 10);
|
c cursor for select * from generate_series(1, 10);
|
||||||
@ -2533,6 +2551,23 @@ $$ language plpgsql;
|
|||||||
|
|
||||||
select * from sc_test();
|
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;
|
||||||
|
move forward all in c;
|
||||||
|
fetch backward from c into x;
|
||||||
|
if found then
|
||||||
|
return next x;
|
||||||
|
end if;
|
||||||
|
close c;
|
||||||
|
end;
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
|
select * from sc_test();
|
||||||
|
|
||||||
drop function sc_test();
|
drop function sc_test();
|
||||||
|
|
||||||
-- test qualified variable names
|
-- test qualified variable names
|
||||||
@ -3084,7 +3119,7 @@ drop function strtest();
|
|||||||
|
|
||||||
DO $$
|
DO $$
|
||||||
DECLARE r record;
|
DECLARE r record;
|
||||||
BEGIN
|
BEGIN
|
||||||
FOR r IN SELECT rtrim(roomno) AS roomno, comment FROM Room ORDER BY roomno
|
FOR r IN SELECT rtrim(roomno) AS roomno, comment FROM Room ORDER BY roomno
|
||||||
LOOP
|
LOOP
|
||||||
RAISE NOTICE '%, %', r.roomno, r.comment;
|
RAISE NOTICE '%, %', r.roomno, r.comment;
|
||||||
@ -3096,7 +3131,7 @@ DO LANGUAGE plpgsql $$begin return 1; end$$;
|
|||||||
|
|
||||||
DO LANGUAGE plpgsql $$
|
DO LANGUAGE plpgsql $$
|
||||||
DECLARE r record;
|
DECLARE r record;
|
||||||
BEGIN
|
BEGIN
|
||||||
FOR r IN SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY roomno
|
FOR r IN SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY roomno
|
||||||
LOOP
|
LOOP
|
||||||
RAISE NOTICE '%, %', r.roomno, r.comment;
|
RAISE NOTICE '%, %', r.roomno, r.comment;
|
||||||
|
Reference in New Issue
Block a user