Thread: Passing result of multirow subquery to C function

Passing result of multirow subquery to C function

From
Magnus Persson
Date:
During the holidays I've taken on to looking at writing a postgres C
extension/function. What I've done so far is more or less the article
series by Ron Peterson (http://linuxgazette.net/142/peterson.html).

What I'm having issues figuring out is how to pass the results of a
subquery to a function (if at all possible?):

SELECT hello((SELECT name FROM names));

Where name is of type TEXT. And results from calling the function is:

hello
------------
Hello, Benny
Hello, Kenny

And what the function does is to only prepend "Hello, " to the string.

My naive attempt errors with:
ERROR: more than one row returned by a subquery used as an expression

What should I be looking at?


Re: Passing result of multirow subquery to C function

From
David Johnston
Date:
Select hello(name) from names

You can only pass a single row to a function.  A work around is to use
arrays but for your example the above form is what you would do and is
typical of function usage in a table context.

David J.



--
View this message in context:
http://postgresql.1045698.n5.nabble.com/Passing-result-of-multirow-subquery-to-C-function-tp5784914p5784915.html
Sent from the PostgreSQL - novice mailing list archive at Nabble.com.


Re: Passing result of multirow subquery to C function

From
Tom Lane
Date:
Magnus Persson <magnus.e.persson@gmail.com> writes:
> What I'm having issues figuring out is how to pass the results of a
> subquery to a function (if at all possible?):

> SELECT hello((SELECT name FROM names));

There's no direct way to do that; we have a notion of a "function
returning set", but not one of a "function accepting set".

The most straightforward thing is to reinterpret the requirement
as
    SELECT hello(name) FROM names;
so that the function just deals with one name at a time.

You could also give the query to the function as a string and
have it execute the query internally (using SPI):
    SELECT hello('SELECT name FROM names');
I find this to be a pretty bad design choice most of the time,
but sometimes there's no good alternative.  There are precedents
in core PG, such as the ts_stat() functions.

            regards, tom lane


Re: Passing result of multirow subquery to C function

From
Merlin Moncure
Date:
On Tue, Dec 31, 2013 at 10:24 AM, David Johnston <polobo@yahoo.com> wrote:
> Select hello(name) from names
>
> You can only pass a single row to a function.  A work around is to use
> arrays but for your example the above form is what you would do and is
> typical of function usage in a table context.

for posterity, you could do arrays with,

SELECT hello(array(select name from names));

if 'name' is text, the function would take TEXT[]. you could also pass
the entire table via:

SELECT hello(array(select n from names n));

in which case the hello function would take names[] and you could pass
through the data in the receiving function with FOREACH or unnest().
This type of invocation is OK, I use it often, but will not scale very
well to large amounts of data passed in to the function.  If you need
industrial passing handling between functions TEMP tables (perhaps
decorated with ON COMMIT DROP) are probably the best way to go but
require some extra care to manage scope and will be slower for the
'just a few records' case.

Yet another way to do it is with refcursors which are basically
cursors you can refer to by string.  If you do use the convention:

SELECT func(col) FROM foo;

I would advise making func() an IMMUTABLE plpgsql function or (even
better) a sql function if it supports inlining.

merlin


Re: Passing result of multirow subquery to C function

From
Gerald Cheves
Date:
Merlin, Thank you for that explanation of passing arrays to a function

- Gerald

On 1/2/2014 12:33 PM, Merlin Moncure wrote:
> On Tue, Dec 31, 2013 at 10:24 AM, David Johnston <polobo@yahoo.com> wrote:
>> Select hello(name) from names
>>
>> You can only pass a single row to a function.  A work around is to use
>> arrays but for your example the above form is what you would do and is
>> typical of function usage in a table context.
> for posterity, you could do arrays with,
>
> SELECT hello(array(select name from names));
>
> if 'name' is text, the function would take TEXT[]. you could also pass
> the entire table via:
>
> SELECT hello(array(select n from names n));
>
> in which case the hello function would take names[] and you could pass
> through the data in the receiving function with FOREACH or unnest().
> This type of invocation is OK, I use it often, but will not scale very
> well to large amounts of data passed in to the function.  If you need
> industrial passing handling between functions TEMP tables (perhaps
> decorated with ON COMMIT DROP) are probably the best way to go but
> require some extra care to manage scope and will be slower for the
> 'just a few records' case.
>
> Yet another way to do it is with refcursors which are basically
> cursors you can refer to by string.  If you do use the convention:
>
> SELECT func(col) FROM foo;
>
> I would advise making func() an IMMUTABLE plpgsql function or (even
> better) a sql function if it supports inlining.
>
> merlin
>
>


--
siamo arrivati sani e salvi