Re: Passing refcursors between pl/pgsql functions

From: Merlin Moncure <mmoncure(at)gmail(dot)com>
To: "Reuven M(dot) Lerner" <reuven(at)lerner(dot)co(dot)il>
Cc: Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>, pgsql-general(at)postgresql(dot)org
Subject: Re: Passing refcursors between pl/pgsql functions
Date: 2010-10-14 13:25:24
Message-ID: AANLkTimXZFtmxXR0VwHzmm_SW7xvzYmdCkA3Cp7m3vCH@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

On Thu, Oct 14, 2010 at 12:31 AM, Reuven M. Lerner <reuven(at)lerner(dot)co(dot)il> wrote:
>
>
> Hi, Merlin.  You wrote:
>
>> In other words, something like this:
>>
>> create or replace function test() returns setof foo as
>> $$
>> declare
>>   r refcursor;
>>   f foo;
>>   i int;
>> begin
>>   open r for select * from foo;
>>
>>   for i in 1..10
>>   loop
>>     fetch 1 from r into f;
>>     exit when not found;
>>     return next f;
>>   end loop;
>> end;
>> $$ language plpgsql;
>>
>> Having defined refcursor separately from the place it is being used
>> really had no bearing on the peculiarities of the 'fetch' statement.
>
> This isn't quite what I was looking for; perhaps I didn't make myself clear.
>
> I want to invoke one function, and get an open refcursor returned.  That
> much, I know how to do.
>
> I then want to be able to call a second function, repeatedly, which will
> essentially perform a "fetch 20" from that open refcursor.  The second
> function should have an input of a refcursor (already open), and should
> return a set of rows from the table on which it was opened.
>
> This isn't the way that I would want to do things, but my client's
> application structure seems to require it, at least for now.  So, is there a
> way to do this?

yes: if you review the example above, the key snippet is:
for i in 1..10
loop
fetch 1 from r into f;
exit when not found;
return next f;
end loop;
Which would make the body of your consumer function. I understand
that you need to do it in separate functions -- that part is easy and
covered via the documentation on cursors. The problem is you can't
direct the ouput of 'fetch n' into the return of a function or some
other variable, except in the special case of 'fetch 1' where we can
use a record variable. So we have to simulate 'fetch 10/20 etc' with
a loop. You can split the function above into two separate functions
and you should have what you want.

A hypothetical improvement to postgresql that would make life
easier/faster would be to allow fetch to be used in a CTE:

with rows as (fetch 20 from r) ...

So you could point it at 'return next', record array, temp table, etc.

merlin

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Gauthier, Dave 2010-10-14 13:50:37 Re: Adding a New Column Specifically In a Table
Previous Message Vick Khera 2010-10-14 13:17:22 Re: Copying data files to new hardware?