'<replaceable>filename</replaceable>', 'retcomposite'
LANGUAGE C IMMUTABLE STRICT;
</programlisting>
A different way is to use OUT parameters:
<programlisting>
CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
OUT f1 integer, OUT f2 integer, OUT f3 integer)
RETURNS SETOF record
AS '<replaceable>filename</replaceable>', 'retcomposite'
LANGUAGE C IMMUTABLE STRICT;
</programlisting>
Notice that in this method the output type of the function is formally
an anonymous <structname>record</structname> type.
</para>
</sect2>
<sect2 id="xfunc-c-polymorphic">
<title>Polymorphic Arguments and Return Types</title>
<para>
C-language functions can be declared to accept and
return the polymorphic types described in <xref
linkend="extend-types-polymorphic"/>.
When a function's arguments or return types
are defined as polymorphic types, the function author cannot know
in advance what data type it will be called with, or
need to return. There are two routines provided in <filename>fmgr.h</filename>
to allow a version-1 C function to discover the actual data types
of its arguments and the type it is expected to return. The routines are
called <literal>get_fn_expr_rettype(FmgrInfo *flinfo)</literal> and
<literal>get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)</literal>.
They return the result or argument type OID, or <symbol>InvalidOid</symbol> if the
information is not available.
The structure <literal>flinfo</literal> is normally accessed as
<literal>fcinfo->flinfo</literal>. The parameter <literal>argnum</literal>
is zero based. <function>get_call_result_type</function> can also be used
as an alternative to <function>get_fn_expr_rettype</function>.
There is also <function>get_fn_expr_variadic</function>, which can be used to
find out whether variadic arguments have been merged into an array.
This is primarily useful for <literal>VARIADIC "any"</literal> functions,
since such merging will always have occurred for variadic functions
taking ordinary array types.
</para>
<para>
For example, suppose we want to write a function to accept a single
element of any type, and return a one-dimensional array of that type:
<programlisting>
PG_FUNCTION_INFO_V1(make_array);
Datum
make_array(PG_FUNCTION_ARGS)
{
ArrayType *result;
Oid element_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
Datum element;
bool isnull;
int16 typlen;
bool typbyval;
char typalign;
int ndims;
int dims[MAXDIM];
int lbs[MAXDIM];
if (!OidIsValid(element_type))
elog(ERROR, "could not determine data type of input");
/* get the provided element, being careful in case it's NULL */
isnull = PG_ARGISNULL(0);
if (isnull)
element = (Datum) 0;
else
element = PG_GETARG_DATUM(0);
/* we have one dimension */
ndims = 1;
/* and one element */
dims[0] = 1;
/* and lower bound is 1 */
lbs[0] = 1;
/* get required info about the element type */
get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
/* now build the array */
result = construct_md_array(&element, &isnull, ndims, dims, lbs,
element_type, typlen, typbyval, typalign);
PG_RETURN_ARRAYTYPE_P(result);
}
</programlisting>
</para>
<para>
The following command declares the function
<function>make_array</function> in SQL:
<programlisting>
CREATE FUNCTION make_array(anyelement) RETURNS anyarray
AS '<replaceable>DIRECTORY</replaceable>/funcs', 'make_array'
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