Plpgsql function with unknown number of args

Started by Relyea, Mikealmost 21 years ago6 messagesgeneral
Jump to latest
#1Relyea, Mike
Mike.Relyea@xerox.com

I need to create my very first function. I'm using 8.0.2 and I need a
function that I can call (from my client app) with an unknown number of
criteria for a select query. The function will then return the results
of the query. In my mind, it would go something like what I've outlined
below. I realize that there are syntax mistakes etc, but this is just
an example:

CREATE TABLE mytable (
a INTEGER UNIQUE PRIMARY KEY,
b VARCHAR(100) NOT NULL,
);

CREATE FUNCTION myfunc(criteria) RETURNS ???? AS $$

BEGIN

BEGIN
FOREACH crit IN criteria
critsql := "b = 'crit' OR "
NEXT crit
END;

PERFORM "SELECT a, b FROM mytable WHERE (" critsql ");"

END;
$$ LANGUAGE plpgsql;

Select * from myfunc(1, 2, 3, 4) would then equate to SELECT a, b FROM
mytable WHERE (b = '1' OR b = '2' OR b = '3' OR b = '4');

Select * from myfunc(9, 21) would equate to SELECT a, b FROM mytable
WHERE (b = '9' OR b = '21');

My question is how do I do that? I've looked through the docs and can't
find what I'm looking for. I'm assuming this is possible because it's a
relatively simple task.

Mike

#2Harald Fuchs
use_reply_to@protecting.net
In reply to: Relyea, Mike (#1)
Re: Plpgsql function with unknown number of args

In article <1806D1F73FCB7F439F2C842EE0627B1801C32853@usa0300ms01.na.xerox.net>,
"Relyea, Mike" <Mike.Relyea@xerox.com> writes:

I need to create my very first function. I'm using 8.0.2 and I need a
function that I can call (from my client app) with an unknown number of
criteria for a select query. The function will then return the results
of the query. In my mind, it would go something like what I've outlined
below. I realize that there are syntax mistakes etc, but this is just
an example:

CREATE TABLE mytable (
a INTEGER UNIQUE PRIMARY KEY,
b VARCHAR(100) NOT NULL,
);

CREATE FUNCTION myfunc(criteria) RETURNS ???? AS $$

BEGIN

BEGIN
FOREACH crit IN criteria
critsql := "b = 'crit' OR "
NEXT crit
END;

PERFORM "SELECT a, b FROM mytable WHERE (" critsql ");"

END;
$$ LANGUAGE plpgsql;

Select * from myfunc(1, 2, 3, 4) would then equate to SELECT a, b FROM
mytable WHERE (b = '1' OR b = '2' OR b = '3' OR b = '4');

Select * from myfunc(9, 21) would equate to SELECT a, b FROM mytable
WHERE (b = '9' OR b = '21');

My question is how do I do that? I've looked through the docs and can't
find what I'm looking for. I'm assuming this is possible because it's a
relatively simple task.

You can't have a variable number of args, but since all args have the
same type you can use an array. The return type is a set of mytable
rows; thus myfunc becomes something like

CREATE FUNCTION myfunc (TEXT[]) RETURNS SETOF mytable AS $$
SELECT *
FROM mytable
WHERE b = ANY ($1)
$$ LANGUAGE sql;

This function can be called like that:

SELECT *
FROM myfunc (ARRAY ['1', '2', '3', '4']);

SELECT *
FROM myfunc (ARRAY ['9', '21']);

#3Tony Caduto
tony_caduto@amsoftwaredesign.com
In reply to: Relyea, Mike (#1)
Re: Plpgsql function with unknown number of args

you coud pass in criteria as a delimted string, then
pull out each arg something like this

CREATE or REPLACE FUNCTION test_func( varchar)
RETURNS pg_catalog.void AS
$BODY$
DECLARE
IN_ARRAY text[] ;
arg1 varchar;
arg2 varchar;
arg3 varchar

begin
IN_ARRAY = string_to_array($1,'~^~');

arg1 = IN_ARRAY[1]
arg2 = IN_ARRAY[2]
arg3 = IN_ARRAY[3]

Then call the function like this:

select test_func('bla^~^bla~^~yada');

This example does not return anything, but you could build a select from the args you passed in then return a cursor.

normally PG is limited to 32 args (unless special compiled to support more), but with this technique you can pass in as many as you want.

hope this helps.

Tony Caduto
AM Software Design
Home of PG Lightning Admin for Postgresql 8.x
http://www.amsoftwaredesign.com

Show quoted text

CREATE FUNCTION myfunc(criteria) RETURNS ???? AS $$

BEGIN

BEGIN
FOREACH crit IN criteria
critsql := "b = 'crit' OR "
NEXT crit
END;

PERFORM "SELECT a, b FROM mytable WHERE (" critsql ");"

END;
$$ LANGUAGE plpgsql;

#4Relyea, Mike
Mike.Relyea@xerox.com
In reply to: Tony Caduto (#3)
Re: Plpgsql function with unknown number of args

Thanks for the input. This looks very promising. I have one further
question. My SQL statement is going to pull data from more than one
table in a relatively complex query. How do I cast the RETURNS portion
of the function? Again, I can't find what I'm looking for in the docs.
I've included an actual sample SQL statement. I will only be changing
the first portion of the WHERE clause.

SELECT "PrintSamples"."MachineID", "PrintSamples"."PrintCopyID",
"tblColors"."Color", "tblBlockAC"."AreaCoverage",
"ParameterValues"."ParameterValue" AS "Mottle_NMF"
FROM ("AnalysisModules"
INNER JOIN ("tblColors"
INNER JOIN ("Targets"
INNER JOIN (("tblTPNamesAndColors"
INNER JOIN "PrintSamples"
ON "tblTPNamesAndColors"."TestPatternName" =
"PrintSamples"."TestPatternName")
INNER JOIN (("DigitalImages"
INNER JOIN "PrintSampleAnalyses"
ON "DigitalImages"."ImageID" = "PrintSampleAnalyses"."ImageID")
INNER JOIN ("ParameterNames"
INNER JOIN ("Measurements"
INNER JOIN "ParameterValues"
ON "Measurements"."MeasurementID" =
"ParameterValues"."MeasurementID")
ON "ParameterNames"."ParameterID" =
"ParameterValues"."ParameterID")
ON "PrintSampleAnalyses"."psaID" = "Measurements"."psaID")
ON "PrintSamples"."PrintSampleID" =
"DigitalImages"."PrintSampleID")
ON "Targets"."TargetID" = "Measurements"."TargetID")
ON "tblColors"."ColorID" = "tblTPNamesAndColors"."ColorID")
ON "AnalysisModules"."MetricID" = "Measurements"."MetricID")
INNER JOIN "tblBlockAC"
ON "Targets"."TargetID" = "tblBlockAC"."TargetID"
WHERE (("PrintSamples"."MachineID" = '2167' OR
"PrintSamples"."MachineID" = '2168' OR "PrintSamples"."MachineID" =
'2169')
AND (("tblBlockAC"."AreaCoverage")=100 Or
("tblBlockAC"."AreaCoverage")=60 Or ("tblBlockAC"."AreaCoverage")=40)
AND (("AnalysisModules"."AnalysisModuleName")='NMF')
AND (("ParameterNames"."ParameterName")='NMF'))
ORDER BY "PrintSamples"."MachineID", "PrintSamples"."PrintCopyID",
"tblColors"."ColorID";

-----Original Message-----
From: pgsql-general-owner@postgresql.org
[mailto:pgsql-general-owner@postgresql.org] On Behalf Of Harald Fuchs
Sent: Monday, April 18, 2005 3:49 PM
To: pgsql-general@postgresql.org
Subject: Re: [GENERAL] Plpgsql function with unknown number of args

In article
<1806D1F73FCB7F439F2C842EE0627B1801C32853@usa0300ms01.na.xerox.net>,
"Relyea, Mike" <Mike.Relyea@xerox.com> writes:

I need to create my very first function. I'm using 8.0.2 and I need a
function that I can call (from my client app) with an unknown number

of

criteria for a select query. The function will then return the

results

of the query. In my mind, it would go something like what I've

outlined

below. I realize that there are syntax mistakes etc, but this is just
an example:

CREATE TABLE mytable (
a INTEGER UNIQUE PRIMARY KEY,
b VARCHAR(100) NOT NULL,
);

CREATE FUNCTION myfunc(criteria) RETURNS ???? AS $$

BEGIN

BEGIN
FOREACH crit IN criteria
critsql := "b = 'crit' OR "
NEXT crit
END;

PERFORM "SELECT a, b FROM mytable WHERE (" critsql ");"

END;
$$ LANGUAGE plpgsql;

Select * from myfunc(1, 2, 3, 4) would then equate to SELECT a, b FROM
mytable WHERE (b = '1' OR b = '2' OR b = '3' OR b = '4');

Select * from myfunc(9, 21) would equate to SELECT a, b FROM mytable
WHERE (b = '9' OR b = '21');

My question is how do I do that? I've looked through the docs and

can't

find what I'm looking for. I'm assuming this is possible because it's

a

relatively simple task.

You can't have a variable number of args, but since all args have the
same type you can use an array. The return type is a set of mytable
rows; thus myfunc becomes something like

CREATE FUNCTION myfunc (TEXT[]) RETURNS SETOF mytable AS $$
SELECT *
FROM mytable
WHERE b = ANY ($1)
$$ LANGUAGE sql;

This function can be called like that:

SELECT *
FROM myfunc (ARRAY ['1', '2', '3', '4']);

SELECT *
FROM myfunc (ARRAY ['9', '21']);

---------------------------(end of broadcast)---------------------------
TIP 3: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to majordomo@postgresql.org so that your
message can get through to the mailing list cleanly

#5Tom Lane
tgl@sss.pgh.pa.us
In reply to: Relyea, Mike (#4)
Re: Plpgsql function with unknown number of args

"Relyea, Mike" <Mike.Relyea@xerox.com> writes:

Thanks for the input. This looks very promising. I have one further
question. My SQL statement is going to pull data from more than one
table in a relatively complex query. How do I cast the RETURNS portion
of the function?

In current releases, you'll have to create a named composite type that
matches what you want to return, and declare the function as returning
that type.

(PG 8.1 will have a facility for named OUT parameters that lets you
avoid the notational overhead of inventing a composite type, although
what happens under-the-hood is not really very different.)

regards, tom lane

#6Tony Caduto
tony_caduto@amsoftwaredesign.com
In reply to: Relyea, Mike (#4)
Re: Plpgsql function with unknown number of args

You don't have to cast it as anything, just return a refcursor from your
function.

Say you return a refcursor called return_cursor

select myfunction(your_in_array);
fetch all from return_cursor;

If you are calling from a development environment, you put the return
value of the fuction (the refcursor name) into a variable, then
dynamicly build the fetch
all statement from return value of the function. This must be done in
the context of a transaction, i.e. both statements must must be executed
in the same transaction.

The refcursors work really well and are very flexible.

Relyea, Mike wrote:

Show quoted text

Thanks for the input. This looks very promising. I have one further
question. My SQL statement is going to pull data from more than one
table in a relatively complex query. How do I cast the RETURNS portion
of the function? Again, I can't find what I'm looking for in the docs.
I've included an actual sample SQL statement. I will only be changing
the first portion of the WHERE clause.