Thread: Passing nulls into PL/pgSQL functions

Passing nulls into PL/pgSQL functions

From
Adam Witney
Date:
Hi,

Is it possible to pass a null value into a PL/pgSQL function. For example

CREATE TABLE mytable(id int, name text);

CREATE OR REPLACE FUNCTION myfunc(int, text) returns int  AS '
 DECLARE
   _id ALIAS FOR $1;
   _name ALIAS FOR $2;

 BEGIN
   EXECUTE ''INSERT INTO mytable (id, name) VALUES(''||_id||'',
''''''||_name||'''''')'';

   RETURN _id;
 END

' LANGUAGE 'plpgsql';

Now, this works ok

select myfunc(1, 'foo');

However, this fails

select myfunc(1, null);

Is there a way of doing it such that I can pass a null sometimes?

Thanks for any help

Adam


--
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.


Re: Passing nulls into PL/pgSQL functions

From
Tom Lane
Date:
Adam Witney <awitney@sghms.ac.uk> writes:
> Is it possible to pass a null value into a PL/pgSQL function.

Certainly.

Your problem is with the EXECUTE, or even more specifically with the
string concatenation expression you're using to build the EXECUTE
expression.  Do you really need an EXECUTE here at all?  If so,
something involving COALESCE would work.  I'd try

EXECUTE ''INSERT ....'' || coalesce(quote_literal(_name), ''NULL'') || '')'';

            regards, tom lane


"ERROR: Argument of WHERE must not be a set function"?

From
Drew Wilson
Date:
I want to use a function to generate a list of OIDs to be used in a
subselect.

However, I can't figure out what to return from my function that will
properly work in a WHERE clause.

I tried:
CREATE FUNCTION myTest() RETURNS SETOF oid AS 'SELECT id FROM foo;'
LANGUAGE SQL;

But when I try:
SELECT * FROM foo WHERE id in in (myTest());

I get this error message:
"ERROR: Argument of WHERE must not be a set function"


How can I use a function to generate my subselect? (I want to cal my
function just once, and avoid calling it once per row.)

Thanks,

Drew


Re: "ERROR: Argument of WHERE must not be a set function"?

From
Dennis Gearon
Date:
a view instead of the function?

Drew Wilson wrote:
> I want to use a function to generate a list of OIDs to be used in a
> subselect.
>
> However, I can't figure out what to return from my function that will
> properly work in a WHERE clause.
>
> I tried:
> CREATE FUNCTION myTest() RETURNS SETOF oid AS 'SELECT id FROM foo;'
> LANGUAGE SQL;
>
> But when I try:
> SELECT * FROM foo WHERE id in in (myTest());
>
> I get this error message:
> "ERROR: Argument of WHERE must not be a set function"
>
>
> How can I use a function to generate my subselect? (I want to cal my
> function just once, and avoid calling it once per row.)
>
> Thanks,
>
> Drew
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 6: Have you searched our list archives?
>
> http://archives.postgresql.org
>


Re: "ERROR: Argument of WHERE must not be a set function"?

From
Drew Wilson
Date:
I have to insert/update/delete into these tables. If I use views, I'd
have to write rules to handle the write-through operations.

I'd like to avoid that extra code.

Drew

On Friday, May 16, 2003, at 04:54 PM, Dennis Gearon wrote:

> a view instead of the function?
>
> Drew Wilson wrote:
>> I want to use a function to generate a list of OIDs to be used in a
>> subselect.
>> However, I can't figure out what to return from my function that will
>> properly work in a WHERE clause.
>> I tried:
>> CREATE FUNCTION myTest() RETURNS SETOF oid AS 'SELECT id FROM foo;'
>> LANGUAGE SQL;
>> But when I try:
>> SELECT * FROM foo WHERE id in in (myTest());
>> I get this error message:
>> "ERROR: Argument of WHERE must not be a set function"
>> How can I use a function to generate my subselect? (I want to cal my
>> function just once, and avoid calling it once per row.)
>> Thanks,
>> Drew
>> ---------------------------(end of
>> broadcast)---------------------------
>> TIP 6: Have you searched our list archives?
>> http://archives.postgresql.org
>
>
> ---------------------------(end of
> broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to
> majordomo@postgresql.org
>


Re: "ERROR: Argument of WHERE must not be a set function"?

From
Stephan Szabo
Date:
On Wed, 16 Apr 2003, Drew Wilson wrote:

> I want to use a function to generate a list of OIDs to be used in a
> subselect.
>
> However, I can't figure out what to return from my function that will
> properly work in a WHERE clause.
>
> I tried:
> CREATE FUNCTION myTest() RETURNS SETOF oid AS 'SELECT id FROM foo;'
> LANGUAGE SQL;
>
> But when I try:
> SELECT * FROM foo WHERE id in in (myTest());

I think the syntax would be:
 select * from foo where id in (select * from myTest())

> I get this error message:
> "ERROR: Argument of WHERE must not be a set function"
>
>
> How can I use a function to generate my subselect? (I want to cal my
> function just once, and avoid calling it once per row.)

I think 7.4 might let you get away with calling the function only once for
the above, but current versions don't AFAIK.  I assume the actual
conditions are more complicated than the above (which could probably be
reformulated into a join manually).


Re: "ERROR: Argument of WHERE must not be a set function"?

From
Drew Wilson
Date:
Oh, also, regarding using a view... I need the SQL statement to pass a
variable to the function, which I'm not sure I can do with a view.

So my example would be more like:
CREATE FUNCTION myTest(text) RETURNS SETOF oid AS 'SELECT id FROM foo
WHERE name = $1;' LANGUAGE SQL;
and
SELECT * FROM foo WHERE id in in (myTest("bar"));

Thanks,

Drew

On Wednesday, April 16, 2003, at 04:58 PM, Drew Wilson wrote:

> I have to insert/update/delete into these tables. If I use views, I'd
> have to write rules to handle the write-through operations.
>
> I'd like to avoid that extra code.
>
> Drew
>
> On Friday, May 16, 2003, at 04:54 PM, Dennis Gearon wrote:
>
>> a view instead of the function?
>>
>> Drew Wilson wrote:
>>> I want to use a function to generate a list of OIDs to be used in a
>>> subselect.
>>> However, I can't figure out what to return from my function that
>>> will properly work in a WHERE clause.
>>> I tried:
>>> CREATE FUNCTION myTest() RETURNS SETOF oid AS 'SELECT id FROM foo;'
>>> LANGUAGE SQL;
>>> But when I try:
>>> SELECT * FROM foo WHERE id in in (myTest());
>>> I get this error message:
>>> "ERROR: Argument of WHERE must not be a set function"
>>> How can I use a function to generate my subselect? (I want to cal my
>>> function just once, and avoid calling it once per row.)
>>> Thanks,
>>> Drew
>>> ---------------------------(end of
>>> broadcast)---------------------------
>>> TIP 6: Have you searched our list archives?
>>> http://archives.postgresql.org
>>
>>
>> ---------------------------(end of
>> broadcast)---------------------------
>> TIP 1: subscribe and unsubscribe commands go to
>> majordomo@postgresql.org
>>
>
>
> ---------------------------(end of
> broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to
> majordomo@postgresql.org
>


Re: "ERROR: Argument of WHERE must not be a set function"?

From
Drew Wilson
Date:
Thank you very much. Yes, "select * from foo where id in (select * from
myTest())" is the syntax I was looking for.

On Wednesday, April 16, 2003, at 05:12 PM, Stephan Szabo wrote:
> On Wed, 16 Apr 2003, Drew Wilson wrote:
>
>> I want to use a function to generate a list of OIDs to be used in a
>> subselect.
>>
>> However, I can't figure out what to return from my function that will
>> properly work in a WHERE clause.
>>
>> I tried:
>> CREATE FUNCTION myTest() RETURNS SETOF oid AS 'SELECT id FROM foo;'
>> LANGUAGE SQL;
>>
>> But when I try:
>> SELECT * FROM foo WHERE id in in (myTest());
>
> I think the syntax would be:
>  select * from foo where id in (select * from myTest())
>
>> I get this error message:
>> "ERROR: Argument of WHERE must not be a set function"
>>
>> How can I use a function to generate my subselect? (I want to cal my
>> function just once, and avoid calling it once per row.)
>
> I think 7.4 might let you get away with calling the function only once
> for
> the above, but current versions don't AFAIK.  I assume the actual
> conditions are more complicated than the above (which could probably be
> reformulated into a join manually).

Yes, the SQL function is a join spanning 5 tables, as well as an OR
clause to test for a null relationship at the top.

Thanks again,

Drew


Re: "ERROR: Argument of WHERE must not be a set function"?

From
Stephan Szabo
Date:
On Wed, 16 Apr 2003, Drew Wilson wrote:

> Thank you very much. Yes, "select * from foo where id in (select * from
> myTest())" is the syntax I was looking for.
>
> On Wednesday, April 16, 2003, at 05:12 PM, Stephan Szabo wrote:
> > On Wed, 16 Apr 2003, Drew Wilson wrote:
> >
> >> I want to use a function to generate a list of OIDs to be used in a
> >> subselect.
> >>
> >> However, I can't figure out what to return from my function that will
> >> properly work in a WHERE clause.
> >>
> >> I tried:
> >> CREATE FUNCTION myTest() RETURNS SETOF oid AS 'SELECT id FROM foo;'
> >> LANGUAGE SQL;
> >>
> >> But when I try:
> >> SELECT * FROM foo WHERE id in in (myTest());
> >
> > I think the syntax would be:
> >  select * from foo where id in (select * from myTest())
> >
> >> I get this error message:
> >> "ERROR: Argument of WHERE must not be a set function"
> >>
> >> How can I use a function to generate my subselect? (I want to cal my
> >> function just once, and avoid calling it once per row.)
> >
> > I think 7.4 might let you get away with calling the function only once
> > for
> > the above, but current versions don't AFAIK.  I assume the actual
> > conditions are more complicated than the above (which could probably be
> > reformulated into a join manually).
>
> Yes, the SQL function is a join spanning 5 tables, as well as an OR
> clause to test for a null relationship at the top.

I wasn't worried about the function (per-se) but the usage.
Select * from foo where id in (select id from myTest())

seems to me anyway pretty equivalent (excepting any possible null related
wierdness) to something like:
select * from foo, (select * from myTest()) bar where foo.id=bar.id

Which should only call the function once.