conditional execution (set-returning
functions inside <literal>CASE</literal> etc.) was previously allowed,
complicating things even more.
Use of the <literal>LATERAL</literal> syntax is recommended when writing
queries that need to work in older <productname>PostgreSQL</productname> versions,
because that will give consistent results across different versions.
If you have a query that is relying on conditional execution of a
set-returning function, you may be able to fix it by moving the
conditional test into a custom set-returning function. For example,
<programlisting>
SELECT x, CASE WHEN y > 0 THEN generate_series(1, z) ELSE 5 END FROM tab;
</programlisting>
could become
<programlisting>
CREATE FUNCTION case_generate_series(cond bool, start int, fin int, els int)
RETURNS SETOF int AS $$
BEGIN
IF cond THEN
RETURN QUERY SELECT generate_series(start, fin);
ELSE
RETURN QUERY SELECT els;
END IF;
END$$ LANGUAGE plpgsql;
SELECT x, case_generate_series(y > 0, 1, z, 5) FROM tab;
</programlisting>
This formulation will work the same in all versions
of <productname>PostgreSQL</productname>.
</para>
</note>
</sect2>
<sect2 id="xfunc-sql-functions-returning-table">
<title><acronym>SQL</acronym> Functions Returning <literal>TABLE</literal></title>
<indexterm>
<primary>function</primary>
<secondary>RETURNS TABLE</secondary>
</indexterm>
<para>
There is another way to declare a function as returning a set,
which is to use the syntax
<literal>RETURNS TABLE(<replaceable>columns</replaceable>)</literal>.
This is equivalent to using one or more <literal>OUT</literal> parameters plus
marking the function as returning <literal>SETOF record</literal> (or
<literal>SETOF</literal> a single output parameter's type, as appropriate).
This notation is specified in recent versions of the SQL standard, and
thus may be more portable than using <literal>SETOF</literal>.
</para>
<para>
For example, the preceding sum-and-product example could also be
done this way:
<programlisting>
CREATE FUNCTION sum_n_product_with_tab (x int)
RETURNS TABLE(sum int, product int) AS $$
SELECT $1 + tab.y, $1 * tab.y FROM tab;
$$ LANGUAGE SQL;
</programlisting>
It is not allowed to use explicit <literal>OUT</literal> or <literal>INOUT</literal>
parameters with the <literal>RETURNS TABLE</literal> notation — you must
put all the output columns in the <literal>TABLE</literal> list.
</para>
</sect2>
<sect2 id="xfunc-sql-polymorphic-functions">
<title>Polymorphic <acronym>SQL</acronym> Functions</title>
<para>
<acronym>SQL</acronym> functions can be declared to accept and
return the polymorphic types described in <xref
linkend="extend-types-polymorphic"/>. Here is a polymorphic
function <function>make_array</function> that builds up an array
from two arbitrary data type elements:
<screen>
CREATE FUNCTION make_array(anyelement, anyelement) RETURNS anyarray AS $$
SELECT ARRAY[$1, $2];
$$ LANGUAGE SQL;
SELECT make_array(1, 2) AS intarray, make_array('a'::text, 'b') AS textarray;
intarray | textarray
----------+-----------
{1,2} | {a,b}
(1 row)
</screen>
</para>
<para>
Notice the use of the typecast <literal>'a'::text</literal>
to specify that the argument is of type <type>text</type>. This is
required if the argument is just a string literal, since otherwise
it would be treated as type
<type>unknown</type>, and array of <type>unknown</type> is not a valid
type.
Without the typecast, you will get errors like this:
<screen>
ERROR: could not determine polymorphic type because input has type unknown
</screen>
</para>
<para>
With <function>make_array</function> declared as above, you must
provide two arguments that are of exactly the same data type; the