Re: calling a function that takes a row type and returns a set of rows

From: "Pavel Stehule" <pavel(dot)stehule(at)gmail(dot)com>
To: "Robert Haas" <robertmhaas(at)gmail(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: calling a function that takes a row type and returns a set of rows
Date: 2008-10-10 20:01:04
Message-ID: 162867790810101301r1aca7d47o9dbf36e27190d3fa@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

Hello

PostgreSQL doesn't support pipe functions, so you cannot do what you
wont. But you should to use SQL SETOF functions, that should be
called in normal context. I dislike this feature, but it should be
useful for you,

try:

create or replace function bar1(foo)
returns setof foo as $$
select 1, $1.b
union all
select 2, $1.b;
$$ language sql;

postgres=# select (bar1(foo)).* from foo;
a | b
---+---
1 | 1
2 | 1
(2 rows)

I thing, so much better and cleaner version is using explicit or
implicit cursor in function

-- implicit cursor
create or replace function bar() returns setof foo as $$
declare r record;
begin
for r in select * from foo loop
r.a := 1;
return next r;
r.a := 2;
return next r;
end loop;
return;
end;
$$ language plpgsql;

postgres=# select * from bar();
a | b
---+---
1 | 1
2 | 1
(2 rows)

-- using explicit cursor (it's more complicated variant, and I thing,
so it's better don't use it)
create or replace function bar(c refcursor) returns setof foo as $$
declare r record;
begin
loop
fetch c into r;
exit when not found;
r.a := 1;
return next r;
r.a := 2;
return next r;
end loop;
return;
end;
$$ language plpgsql;

begin;
declare x cursor for select * from foo;
select * from bar('x'::refcursor);
commit;

postgres=# declare x cursor for select * from foo;
DECLARE CURSOR
postgres=# select * from bar('x'::refcursor);
a | b
---+---
1 | 1
2 | 1
(2 rows)

postgres=# commit;
COMMIT

Regards
Pavel Stehule

2008/10/10 Robert Haas <robertmhaas(at)gmail(dot)com>:
> So, say I have something like this - the actual example is something a
> bit more useful:
>
> CREATE TABLE foo (a integer, b integer);
> INSERT INTO foo VALUES (1, 1); -- must have some data to generate the failure
>
> CREATE FUNCTION bar (foo) RETURNS SETOF foo AS $$
> DECLARE
> f foo;
> BEGIN
> f.a := 1;
> RETURN NEXT f;
> f.a := 2;
> RETURN NEXT f;
> END
> $$ LANGUAGE plpgsql;
>
> I can't find any legal way of calling this function.
>
> SELECT bar(f) FROM foo f;
> ERROR: set-valued function called in context that cannot accept a set
>
> SELECT * FROM foo f, bar(f);
> ERROR: function expression in FROM may not refer to other relations
> of same query level
>
> Any help appreciated.
>
> Thanks,
>
> ...Robert
>
> --
> Sent via pgsql-general mailing list (pgsql-general(at)postgresql(dot)org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-general
>

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Robert Haas 2008-10-10 20:08:34 Re: calling a function that takes a row type and returns a set of rows
Previous Message Robert Haas 2008-10-10 19:22:14 calling a function that takes a row type and returns a set of rows