Thread: How does one return rows from plpgsql functions?

How does one return rows from plpgsql functions?

From
Ryan Kirkpatrick
Date:
    I seemed to have hit a brick wall in some development work with
pgsql. I want to write a plpgsql function that returns a single row of
table data, i.e. a set of fields. Now, from the documentation, I was able
to figure out that one puts the name of the table that defines the row I
want to return as the return data type. I then declare a variable of
that table's row type, and assign it using a SELECT INTO ..., and then
return that variable. This is roughly the structure I am using:

CREATE FUNCTION update_get (int) RETURNS simple AS '
  DECLARE
    ident ALIAS for $1;
    data simple%ROWTYPE;
  BEGIN
    SELECT INTO data * FROM simple WHERE id = ident;
    RETURN data;
  END;
' LANGUAGE 'plpgsql';

The table 'simple' just has a few simple fields (int, text, and
timestamp). When I execute this function, "SELECT update_get(1);" (and
there is a row with id = 1 in that table), I get back a single, large
number (an oid?):

 update_them
-------------
 2197312
(1 row)

Instead of the set of fields that make up a row of table 'simple'. How do
I get the field data? I tried "SELECT update_get(1).id;" but that gives a
syntax error. And "SELECT id(update_get(1));" rewards me with a backend
crash. :( What am I missing here? Thank you in advance for your help.

    PS. This is pgsql 7.1.0 on a Sparc 20 running Debian 2.2 (potato).

    PPS. I tried to search the mailing list archives first, but
fts.postgresql.org always gives me an under construction error on every
search.

---------------------------------------------------------------------------
|   "For to me to live is Christ, and to die is gain."                    |
|                                            --- Philippians 1:21 (KJV)   |
---------------------------------------------------------------------------
|   Ryan Kirkpatrick  |  Boulder, Colorado  |  http://www.rkirkpat.net/   |
---------------------------------------------------------------------------


Re: How does one return rows from plpgsql functions?

From
Tom Lane
Date:
Ryan Kirkpatrick <pgsql@rkirkpat.net> writes:
> I get the field data? I tried "SELECT update_get(1).id;" but that gives a
> syntax error.

Yeah, that's something we ought to allow.  Maybe for 7.3.

> And "SELECT id(update_get(1));" rewards me with a backend
> crash. :(

Works okay for me in current sources.  Time to update ...

            regards, tom lane

Re: How does one return rows from plpgsql functions?

From
Ryan Kirkpatrick
Date:
On Sat, 19 Jan 2002, Tom Lane wrote:

> Ryan Kirkpatrick <pgsql@rkirkpat.net> writes:
> > And "SELECT id(update_get(1));" rewards me with a backend
> > crash. :(
>
> Works okay for me in current sources.  Time to update ...

    Okay, once I updated to 7.2b5, that select statement started
working just fine for me. :)
    Though I have hit another problem, if I want to display multiple
fields from the returned row, the function executes again for each
field. I.e. 'SELECT id(update_get(1), fielda(update_get(1), ...' will
result in both the values for id and fielda being displayed, but will
execute update_get() twice. This is not only inefficient, but also
undesireable (esp if update_get() modified something that was only to be
modified once for a single row reterival).
    So, how do I get back and access the entire row returned from a
function without calling it multiple times? Or is that even possible?
Thanks.

---------------------------------------------------------------------------
|   "For to me to live is Christ, and to die is gain."                    |
|                                            --- Philippians 1:21 (KJV)   |
---------------------------------------------------------------------------
|   Ryan Kirkpatrick  |  Boulder, Colorado  |  http://www.rkirkpat.net/   |
---------------------------------------------------------------------------


Re: How does one return rows from plpgsql functions?

From
Tom Lane
Date:
Ryan Kirkpatrick <pgsql@rkirkpat.net> writes:
>     So, how do I get back and access the entire row returned from a
> function without calling it multiple times?

You don't.  The syntax just doesn't support it, and no I don't want to
put in common-subexpression recognition.

We have talked about functions as table sources:

    SELECT t.col1, t.col2 FROM myfunction(yaddayadda) AS t;

in which presumably the function would only be invoked once (per row?).
Alex Pilosov was working on this, IIRC, but I dunno when it will be done.

            regards, tom lane

Re: How does one return rows from plpgsql functions?

From
Holger Krug
Date:
On Mon, Jan 21, 2002 at 08:02:46AM -0700, Ryan Kirkpatrick wrote:
>     So, how do I get back and access the entire row returned from a
> function without calling it multiple times? Or is that even possible?
> Thanks.

As I known, their is no straight way to do it. But you can do the
following:

SELECT get_id(p), get_fielda(p) WHERE p = update_get(1);

Here `update_get' allocates space in a memory context like
`CurrentTransactionContext' or what ever is necessary in your case,
puts the resulting typle into the allocated space and returns a
pointer p to that tuple. `get_*' are accessor methods for such a
pointer, accessing the allocated memory and retrieving the values
needed.

To be as type-safe as possible I would recommend to introduce a
special type `PointerToMyTableRow'. The input and output functions of
that type should simply throw an exception (i.e. call
`elog(ERROR,...)'), to avoid that pointers can be externalized.

This all obviously requires some C-coding. But it works and would
solve your problem.


--
Holger Krug
hkrug@rationalizer.com

Re: How does one return rows from plpgsql functions?

From
Holger Krug
Date:
On Mon, Jan 21, 2002 at 07:16:24PM +0100, Holger Krug wrote:
> SELECT get_id(p), get_fielda(p) WHERE p = update_get(1);

Sorry this was wrong. Obviously it should be:

 SELECT get_id(t.p), get_fielda(t.p) FROM (SELECT update_get(1) as p) as t;

resp.:

 SELECT get_id(p), get_fielda(p) FROM (SELECT update_get(1) as p) as NN;

--
Holger Krug
hkrug@rationalizer.com

Re: How does one return rows from plpgsql functions?

From
Ryan Kirkpatrick
Date:
On Mon, 21 Jan 2002, Holger Krug wrote:

> On Mon, Jan 21, 2002 at 08:02:46AM -0700, Ryan Kirkpatrick wrote:
> >     So, how do I get back and access the entire row returned from a
> > function without calling it multiple times? Or is that even possible?
> > Thanks.
>
> As I known, their is no straight way to do it. But you can do the
> following:
>
>  SELECT get_id(t.p), get_fielda(t.p) FROM (SELECT update_get(1) as p) as t;
>
> Here `update_get' allocates space in a memory context like
> `CurrentTransactionContext' or what ever is necessary in your case,
> puts the resulting typle into the allocated space and returns a
> pointer p to that tuple. `get_*' are accessor methods for such a
> pointer, accessing the allocated memory and retrieving the values
> needed.

    Hmm... That looks similar to what Tom had suggested might
eventually be supported. Would be a nice, clean, simple solution that
falls in line with standard SQL syntax.

> This all obviously requires some C-coding. But it works and would
> solve your problem.

    Ahh... That is how one does it now, vs. waiting until some one
implements a higher level version to be used from plpgsql. My need to
return is rows from a function (non-trigger) is not worth writing C
functions, at least not yet. Thanks for the help anyway, I will use your
suggestion as a starting point should I need to go that way. TTYL.

---------------------------------------------------------------------------
|   "For to me to live is Christ, and to die is gain."                    |
|                                            --- Philippians 1:21 (KJV)   |
---------------------------------------------------------------------------
|   Ryan Kirkpatrick  |  Boulder, Colorado  |  http://www.rkirkpat.net/   |
---------------------------------------------------------------------------