1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Support "variadic" functions, which can accept a variable number of arguments

so long as all the trailing arguments are of the same (non-array) type.
The function receives them as a single array argument (which is why they
have to all be the same type).

It might be useful to extend this facility to aggregates, but this patch
doesn't do that.

This patch imposes a noticeable slowdown on function lookup --- a follow-on
patch will fix that by adding a redundant column to pg_proc.

Pavel Stehule
This commit is contained in:
Tom Lane
2008-07-16 01:30:23 +00:00
parent 2c773296f8
commit d89737d31c
38 changed files with 915 additions and 170 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.168 2008/07/14 00:51:45 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.169 2008/07/16 01:30:21 tgl Exp $ -->
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
-->
@ -3643,7 +3643,8 @@
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
<entry>
An array with the data types of the function arguments. This includes
only input arguments (including <literal>INOUT</literal> arguments), and thus represents
only input arguments (including <literal>INOUT</literal> and
<literal>VARIADIC</> arguments), and thus represents
the call signature of the function
</entry>
</row>
@ -3654,8 +3655,9 @@
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
<entry>
An array with the data types of the function arguments. This includes
all arguments (including <literal>OUT</literal> and <literal>INOUT</literal> arguments); however, if all the
arguments are IN arguments, this field will be null.
all arguments (including <literal>OUT</literal> and
<literal>INOUT</literal> arguments); however, if all the
arguments are <literal>IN</literal> arguments, this field will be null.
Note that subscripting is 1-based, whereas for historical reasons
<structfield>proargtypes</> is subscripted from 0
</entry>
@ -3669,8 +3671,10 @@
An array with the modes of the function arguments, encoded as
<literal>i</literal> for <literal>IN</> arguments,
<literal>o</literal> for <literal>OUT</> arguments,
<literal>b</literal> for <literal>INOUT</> arguments.
If all the arguments are <literal>IN</literal> arguments, this field will be null.
<literal>b</literal> for <literal>INOUT</> arguments,
<literal>v</literal> for <literal>VARIADIC</> arguments.
If all the arguments are <literal>IN</literal> arguments,
this field will be null.
Note that subscripts correspond to positions of
<structfield>proallargtypes</> not <structfield>proargtypes</>
</entry>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/extend.sgml,v 1.36 2007/08/31 21:33:48 momjian Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/extend.sgml,v 1.37 2008/07/16 01:30:21 tgl Exp $ -->
<chapter id="extend">
<title>Extending <acronym>SQL</acronym></title>
@ -254,6 +254,16 @@
is equivalent to declaring it as <literal>f(anyenum, anyenum)</>:
both actual arguments have to be the same enum type.
</para>
<para>
A variadic function (one taking a variable number of arguments, as in
<xref linkend="xfunc-sql-variadic-functions">) can be
polymorphic: this is accomplished by declaring its last parameter as
<literal>VARIADIC</> <type>anyarray</>. For purposes of argument
matching and determining the actual result type, such a function behaves
the same as if you had written the appropriate number of
<type>anynonarray</> parameters.
</para>
</sect2>
</sect1>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.131 2008/06/27 01:52:59 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.132 2008/07/16 01:30:21 tgl Exp $ -->
<chapter id="plpgsql">
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
@ -121,6 +121,13 @@
calling query, as discussed in <xref linkend="queries-tablefunctions">.
</para>
<para>
<application>PL/pgSQL</> functions can be declared to accept a variable
number of arguments by using the <literal>VARIADIC</> marker. This
works exactly the same way as for SQL functions, as discussed in
<xref linkend="xfunc-sql-variadic-functions">.
</para>
<para>
<application>PL/pgSQL</> functions can also be declared to accept
and return the polymorphic types

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_function.sgml,v 1.15 2007/09/03 18:46:29 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_function.sgml,v 1.16 2008/07/16 01:30:21 tgl Exp $
PostgreSQL documentation
-->
@ -81,13 +81,14 @@ where <replaceable class="PARAMETER">action</replaceable> is one of:
<listitem>
<para>
The mode of an argument: either <literal>IN</>, <literal>OUT</>,
or <literal>INOUT</>. If omitted, the default is <literal>IN</>.
The mode of an argument: <literal>IN</>, <literal>OUT</>,
<literal>INOUT</>, or <literal>VARIADIC</>.
If omitted, the default is <literal>IN</>.
Note that <command>ALTER FUNCTION</command> does not actually pay
any attention to <literal>OUT</> arguments, since only the input
arguments are needed to determine the function's identity.
So it is sufficient to list the <literal>IN</> and <literal>INOUT</>
arguments.
So it is sufficient to list the <literal>IN</>, <literal>INOUT</>,
and <literal>VARIADIC</> arguments.
</para>
</listitem>
</varlistentry>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/comment.sgml,v 1.36 2007/08/21 21:08:47 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/comment.sgml,v 1.37 2008/07/16 01:30:21 tgl Exp $
PostgreSQL documentation
-->
@ -136,13 +136,14 @@ COMMENT ON
<listitem>
<para>
The mode of a function argument: either <literal>IN</>, <literal>OUT</>,
or <literal>INOUT</>. If omitted, the default is <literal>IN</>.
The mode of a function argument: <literal>IN</>, <literal>OUT</>,
<literal>INOUT</>, or <literal>VARIADIC</>.
If omitted, the default is <literal>IN</>.
Note that <command>COMMENT ON FUNCTION</command> does not actually pay
any attention to <literal>OUT</> arguments, since only the input
arguments are needed to determine the function's identity.
So it is sufficient to list the <literal>IN</> and <literal>INOUT</>
arguments.
So it is sufficient to list the <literal>IN</>, <literal>INOUT</>,
and <literal>VARIADIC</> arguments.
</para>
</listitem>
</varlistentry>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.78 2007/09/11 00:06:41 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.79 2008/07/16 01:30:21 tgl Exp $
-->
<refentry id="SQL-CREATEFUNCTION">
@ -101,8 +101,9 @@ CREATE [ OR REPLACE ] FUNCTION
<listitem>
<para>
The mode of an argument: either <literal>IN</>, <literal>OUT</>,
or <literal>INOUT</>. If omitted, the default is <literal>IN</>.
The mode of an argument: <literal>IN</>, <literal>OUT</>,
<literal>INOUT</>, or <literal>VARIADIC</>.
If omitted, the default is <literal>IN</>.
</para>
</listitem>
</varlistentry>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/drop_function.sgml,v 1.33 2007/01/31 23:26:03 momjian Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/drop_function.sgml,v 1.34 2008/07/16 01:30:21 tgl Exp $
PostgreSQL documentation
-->
@ -65,13 +65,14 @@ DROP FUNCTION [ IF EXISTS ] <replaceable class="parameter">name</replaceable> (
<listitem>
<para>
The mode of an argument: either <literal>IN</>, <literal>OUT</>,
or <literal>INOUT</>. If omitted, the default is <literal>IN</>.
The mode of an argument: <literal>IN</>, <literal>OUT</>,
<literal>INOUT</>, or <literal>VARIADIC</>.
If omitted, the default is <literal>IN</>.
Note that <command>DROP FUNCTION</command> does not actually pay
any attention to <literal>OUT</> arguments, since only the input
arguments are needed to determine the function's identity.
So it is sufficient to list the <literal>IN</> and <literal>INOUT</>
arguments.
So it is sufficient to list the <literal>IN</>, <literal>INOUT</>,
and <literal>VARIADIC</> arguments.
</para>
</listitem>
</varlistentry>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/typeconv.sgml,v 1.54 2008/07/11 07:02:43 petere Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/typeconv.sgml,v 1.55 2008/07/16 01:30:21 tgl Exp $ -->
<chapter Id="typeconv">
<title>Type Conversion</title>
@ -503,6 +503,18 @@ different argument types are considered on an equal footing regardless of
search path position.
</para>
</step>
<step performance="optional">
<para>
If a function is declared with a <literal>VARIADIC</> array parameter, and
the call does not use the <literal>VARIADIC</> keyword, then the function
is treated as if the array parameter were replaced by one or more occurrences
of its element type, as needed to match the call. After such expansion the
function might have effective argument types identical to some non-variadic
function. In that case the function appearing earlier in the search path is
used, or if the two functions are in the same schema, the non-variadic one is
selected.
</para>
</step>
</substeps>
</step>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.130 2007/11/10 20:14:36 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.131 2008/07/16 01:30:21 tgl Exp $ -->
<sect1 id="xfunc">
<title>User-Defined Functions</title>
@ -495,7 +495,7 @@ SELECT getname(new_emp());
None
(1 row)
</screen>
</para>
</para>
<para>
Still another way to use a function that returns a composite type is to
@ -505,7 +505,7 @@ SELECT getname(new_emp());
</sect2>
<sect2 id="xfunc-output-parameters">
<title>Functions with Output Parameters</title>
<title><acronym>SQL</> Functions with Output Parameters</title>
<indexterm>
<primary>function</primary>
@ -578,9 +578,75 @@ DROP FUNCTION sum_n_product (int, int);
<para>
Parameters can be marked as <literal>IN</> (the default),
<literal>OUT</>, or <literal>INOUT</>. An <literal>INOUT</>
<literal>OUT</>, <literal>INOUT</>, or <literal>VARIADIC</>.
An <literal>INOUT</>
parameter serves as both an input parameter (part of the calling
argument list) and an output parameter (part of the result record type).
<literal>VARIADIC</> parameters are input parameters, but are treated
specially as described next.
</para>
</sect2>
<sect2 id="xfunc-sql-variadic-functions">
<title><acronym>SQL</> Functions with Variable Numbers of Arguments</title>
<indexterm>
<primary>function</primary>
<secondary>variadic</secondary>
</indexterm>
<indexterm>
<primary>variadic function</primary>
</indexterm>
<para>
<acronym>SQL</acronym> functions can be declared to accept
variable numbers of arguments, so long as all the <quote>optional</>
arguments are of the same data type. The optional arguments will be
passed to the function as an array. The function is declared by
marking the last parameter as <literal>VARIADIC</>; this parameter
must be declared as being of an array type. For example:
<screen>
CREATE FUNCTION mleast(VARIADIC numeric[]) RETURNS numeric AS $$
SELECT min($1[i]) FROM generate_subscripts($1, 1) g(i);
$$ LANGUAGE SQL;
SELECT mleast(10, -1, 5, 4.4);
mleast
--------
-1
(1 row)
</screen>
Effectively, all the actual arguments at or beyond the
<literal>VARIADIC</> position are gathered up into a one-dimensional
array, as if you had written
<screen>
SELECT mleast(ARRAY[10, -1, 5, 4.4]); -- doesn't work
</screen>
You can't actually write that, though &mdash; or at least, it will
not match this function definition. A parameter marked
<literal>VARIADIC</> matches one or more occurrences of its element
type, not of its own type.
</para>
<para>
Sometimes it is useful to be able to pass an already-constructed array
to a variadic function; this is particularly handy when one variadic
function wants to pass on its array parameter to another one. You can
do that by specifying <literal>VARIADIC</> in the call:
<screen>
SELECT mleast(VARIADIC ARRAY[10, -1, 5, 4.4]);
</screen>
This prevents expansion of the function's variadic parameter into its
element type, thereby allowing the array argument value to match
normally. <literal>VARIADIC</> can only be attached to the last
actual argument of a function call.
</para>
</sect2>
@ -795,13 +861,45 @@ DETAIL: A function returning a polymorphic type must have at least one polymorp
For example:
<screen>
CREATE FUNCTION dup (f1 anyelement, OUT f2 anyelement, OUT f3 anyarray)
AS 'select $1, array[$1,$1]' LANGUAGE sql;
AS 'select $1, array[$1,$1]' LANGUAGE SQL;
SELECT * FROM dup(22);
f2 | f3
----+---------
22 | {22,22}
(1 row)
</screen>
</para>
<para>
Polymorphism can also be used with variadic functions.
For example:
<screen>
CREATE FUNCTION anyleast (VARIADIC anyarray) RETURNS anyelement AS $$
SELECT min($1[i]) FROM generate_subscripts($1, 1) g(i);
$$ LANGUAGE SQL;
SELECT anyleast(10, -1, 5, 4);
anyleast
----------
-1
(1 row)
SELECT anyleast('abc'::text, 'def');
anyleast
----------
abc
(1 row)
CREATE FUNCTION concat(text, VARIADIC anyarray) RETURNS text AS $$
SELECT array_to_string($2, $1);
$$ LANGUAGE SQL;
SELECT concat('|', 1, 4, 2);
concat
--------
1|4|2
(1 row)
</screen>
</para>
</sect2>
@ -852,6 +950,16 @@ CREATE FUNCTION test(smallint, double precision) RETURNS ...
avoid the problem by not choosing conflicting names.
</para>
<para>
Another possible conflict is between variadic and non-variadic functions.
For instance, it is possible to create both <literal>foo(numeric)</> and
<literal>foo(VARIADIC numeric[])</>. In this case it is unclear which one
should be matched to a call providing a single numeric argument, such as
<literal>foo(10.1)</>. The rule is that the function appearing
earlier in the search path is used, or if the two functions are in the
same schema, the non-variadic one is preferred.
</para>
<para>
When overloading C-language functions, there is an additional
constraint: The C name of each function in the family of
@ -2952,7 +3060,25 @@ CREATE FUNCTION make_array(anyelement) RETURNS anyarray
LANGUAGE C IMMUTABLE;
</programlisting>
</para>
<para>
There is a variant of polymorphism that is only available to C-language
functions: they can be declared to take parameters of type
<literal>"any"</>. (Note that this type name must be double-quoted,
since it's also a SQL reserved word.) This works like
<type>anyelement</> except that it does not constrain different
<literal>"any"</> arguments to be the same type, nor do they help
determine the function's result type. A C-language function can also
declare its final parameter to be <literal>VARIADIC "any"</>. This will
match one or more actual arguments of any type (not necessarily the same
type). These arguments will <emphasis>not</> be gathered into an array
as happens with normal variadic functions; they will just be passed to
the function separately. The <function>PG_NARGS()</> macro and the
methods described above must be used to determine the number of actual
arguments and their types when using this feature.
</para>
</sect2>
<sect2>
<title>Shared Memory and LWLocks</title>