Thread: How does one return rows from plpgsql functions?
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/ | ---------------------------------------------------------------------------
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
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/ | ---------------------------------------------------------------------------
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
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
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
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/ | ---------------------------------------------------------------------------