I am trying to write a PL/pgSQL function with optional arguments. It performs a query based on a filtered set of records (if specified), otherwise performs a query on the entire data set in a table.
For example (PSEUDO CODE):
CREATE OR REPLACE FUNCTION foofunc(param1 integer, param2 date, param2 date, optional_list_of_ids=[]) RETURNS SETOF RECORD AS $$
IF len(optional_list_of_ids) > 0 THEN
RETURN QUERY (SELECT * from foobar where f1=param1 AND f2=param2 AND id in optional_list_of_ids);
ELSE
RETURN QUERY (SELECT * from foobar where f1=param1 AND f2=param2);
ENDIF
$$ LANGUAGE SQL;
What would be the correct way to implement this function?
As an aside, I would like to know how I could call such a function in another outer function. This is how I would do it - is it correct, or is there a better way?
CREATE FUNCTION foofuncwrapper(param1 integer, param2 date, param2 date) RETURNS SETOF RECORD AS $$
BEGIN
CREATE TABLE ids AS SELECT id from foobar where id < 100;
RETURN QUERY (SELECT * FROM foofunc(param1, param2, ids));
END
$$ LANGUAGE SQL
Since PostgreSQL 8.4 (which you seem to be running), there are default values for function parameters. If you put your parameter last and provide a default, you can simply omit it from the call:
Major points:
The keyword
DEFAULT
is used to declare parameter defaults. Short alternative:=
.I removed the redundant
param1
from the messy example.Since you return
SELECT * FROM foobar
, declare the return type asRETURNS SETOF foobar
instead ofRETURNS SETOF record
. The latter form with anonymous records is very unwieldy, you'd have to provide a column definition list with every call.I use an array of integer (
int[]
) as function parameter. Adapted theIF
expression and theWHERE
clause accordingly.IF
statements are not available in plain SQL. Has to beLANGUAGE plpgsql
for that.Call with or without
_ids
:Effectively the same:
You have to make sure the call is unambiguous. If you have another function of the same name and two parameters, Postgres might not know which to pick. Explicit casting (like I demonstrate) narrows it down. Else, untyped string literals work, too, but being explicit never hurts.
Call from within another function:
You mean SQL Functions with Variable Numbers of Arguments? If so, use VARIADIC.
Elaborating on Frank's answer on this thread:
The
VARIADIC
agument doesn't have to be the only argument, only the last one.You can use
VARIADIC
for functions that may take zero variadic arguments, it's just a little fiddlier in that it requires a different calling style for zero args. You can provide a wrapper function to hide the ugliness. Given an initial varardic function definition like:For zero args use a wrapper like:
or just call the main func with an empty array like
VARIADIC '{}'::integer[]
directly. The wrapper is ugly, but it's contained ugliness, so I'd recommend using a wrapper.Direct calls can be made in variadic form:
... or array call form with array ctor:
... or array text literal form:
The latter two forms work with empty arrays.