Default values for function arguments

Pavel Stehule, with some tweaks by Peter Eisentraut
This commit is contained in:
Peter Eisentraut 2008-12-04 17:51:28 +00:00
parent 7b640b0345
commit 455dffbb73
29 changed files with 2848 additions and 2166 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.460 2008/11/14 00:51:46 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.461 2008/12/04 17:51:26 petere Exp $ -->
<chapter id="functions"> <chapter id="functions">
<title>Functions and Operators</title> <title>Functions and Operators</title>
@ -11710,6 +11710,10 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<primary>pg_get_function_arguments</primary> <primary>pg_get_function_arguments</primary>
</indexterm> </indexterm>
<indexterm>
<primary>pg_get_function_identity_arguments</primary>
</indexterm>
<indexterm> <indexterm>
<primary>pg_get_function_result</primary> <primary>pg_get_function_result</primary>
</indexterm> </indexterm>
@ -11799,7 +11803,12 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<row> <row>
<entry><literal><function>pg_get_function_arguments</function>(<parameter>func_oid</parameter>)</literal></entry> <entry><literal><function>pg_get_function_arguments</function>(<parameter>func_oid</parameter>)</literal></entry>
<entry><type>text</type></entry> <entry><type>text</type></entry>
<entry>get argument list for function</entry> <entry>get argument list of function's definition (with default values)</entry>
</row>
<row>
<entry><literal><function>pg_get_function_identity_arguments</function>(<parameter>func_oid</parameter>)</literal></entry>
<entry><type>text</type></entry>
<entry>get argument list to identify a function (without argument names, default values)</entry>
</row> </row>
<row> <row>
<entry><literal><function>pg_get_function_result</function>(<parameter>func_oid</parameter>)</literal></entry> <entry><literal><function>pg_get_function_result</function>(<parameter>func_oid</parameter>)</literal></entry>
@ -11920,7 +11929,12 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
of a function, in the form it would need to appear in within of a function, in the form it would need to appear in within
<command>CREATE FUNCTION</>. <command>CREATE FUNCTION</>.
<function>pg_get_function_result</function> similarly returns the <function>pg_get_function_result</function> similarly returns the
appropriate <literal>RETURNS</> clause for the function. appropriate <literal>RETURNS</> clause for the function.
<function>pg_get_function_identity_arguments</function> returns the
argument list necessary to identify a function, in the form it
would need to appear in within <command>ALTER FUNCTION</>, for
instance. This form omits default values and argument names, for
example.
</para> </para>
<para> <para>

View File

@ -1,5 +1,5 @@
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.81 2008/11/14 10:22:46 petere Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.82 2008/12/04 17:51:26 petere Exp $
--> -->
<refentry id="SQL-CREATEFUNCTION"> <refentry id="SQL-CREATEFUNCTION">
@ -21,7 +21,7 @@ $PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.81 2008/11/14 10:22
<refsynopsisdiv> <refsynopsisdiv>
<synopsis> <synopsis>
CREATE [ OR REPLACE ] FUNCTION CREATE [ OR REPLACE ] FUNCTION
<replaceable class="parameter">name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) <replaceable class="parameter">name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [ { DEFAULT | = } <replaceable class="parameter">defexpr</replaceable>] [, ...] ] )
[ RETURNS <replaceable class="parameter">rettype</replaceable> [ RETURNS <replaceable class="parameter">rettype</replaceable>
| RETURNS TABLE ( <replaceable class="parameter">colname</replaceable> <replaceable class="parameter">coltype</replaceable> [, ...] ) ] | RETURNS TABLE ( <replaceable class="parameter">colname</replaceable> <replaceable class="parameter">coltype</replaceable> [, ...] ) ]
{ LANGUAGE <replaceable class="parameter">langname</replaceable> { LANGUAGE <replaceable class="parameter">langname</replaceable>
@ -154,6 +154,20 @@ CREATE [ OR REPLACE ] FUNCTION
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><replaceable class="parameter">defexpr</replaceable></term>
<listitem>
<para>
An expression to be used as default value if the parameter is
not specified. The expression has to be convertable to the
argument type of the parameter. All parameters after a
parameter with default value have to be parameters with default
values as well.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><replaceable class="parameter">rettype</replaceable></term> <term><replaceable class="parameter">rettype</replaceable></term>
@ -667,6 +681,14 @@ COMMIT;
either before or after <replaceable class="parameter">argname</replaceable>. either before or after <replaceable class="parameter">argname</replaceable>.
But only the first way is standard-compliant. But only the first way is standard-compliant.
</para> </para>
<para>
The SQL standard does not specify parameter defaults. The syntax
with the <literal>DEFAULT</literal> key word is from Oracle, and it
is somewhat in the spirit of the standard: SQL/PSM uses it for
variable default values. The syntax with <literal>=</literal> is
used in T-SQL and Firebird.
</para>
</refsect1> </refsect1>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.133 2008/10/31 19:37:56 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.134 2008/12/04 17:51:26 petere Exp $ -->
<sect1 id="xfunc"> <sect1 id="xfunc">
<title>User-Defined Functions</title> <title>User-Defined Functions</title>
@ -663,6 +663,60 @@ SELECT mleast(VARIADIC ARRAY[10, -1, 5, 4.4]);
</para> </para>
</sect2> </sect2>
<sect2 id="xfunc-parameter-defaults">
<title><acronym>SQL</> Functions with Parameters Default Values</title>
<indexterm>
<primary>default values</primary>
</indexterm>
<para>
Functions can be declared with parameters with default values or
expressions. The default expressions are used as parameter value
if the parameter is not explicitly specified in a function call.
All parameters after a a parameter with default value have to be
parameters with default values as well.
</para>
<para>
For example:
<screen>
CREATE FUNCTION foo(a int DEFAULT 1, b int DEFAULT 2, c int DEFAULT 3)
RETURNS int
LANGUAGE SQL
AS $$
SELECT $1 + $2 + $3;
$$;
SELECT foo(10, 20, 30);
foo
-----
60
(1 row)
SELECT foo(10, 20);
foo
-----
33
(1 row)
SELECT foo(10);
foo
-----
15
(1 row)
SELECT foo();
foo
-----
6
(1 row)
</screen>
Instead of the key word <literal>DEFAULT</literal>,
the <literal>=</literal> sign can also be used.
</para>
</sect2>
<sect2 id="xfunc-sql-table-functions"> <sect2 id="xfunc-sql-table-functions">
<title><acronym>SQL</acronym> Functions as Table Sources</title> <title><acronym>SQL</acronym> Functions as Table Sources</title>

View File

@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.112 2008/09/09 18:58:08 tgl Exp $ * $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.113 2008/12/04 17:51:26 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -571,6 +571,11 @@ TypeIsVisible(Oid typid)
* If expand_variadic is false, variadic arguments are not treated specially, * If expand_variadic is false, variadic arguments are not treated specially,
* and the returned nvargs will always be zero. * and the returned nvargs will always be zero.
* *
* If expand_variadic is true, functions with argument default values
* will also be retrieved. If expand_variadic is false, default
* values will not be taken into account and functions that do not
* have exactly nargs arguments in total will not be considered.
*
* We search a single namespace if the function name is qualified, else * We search a single namespace if the function name is qualified, else
* all namespaces in the search path. The return list will never contain * all namespaces in the search path. The return list will never contain
* multiple entries with identical argument lists --- in the multiple- * multiple entries with identical argument lists --- in the multiple-
@ -621,13 +626,45 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
int pathpos = 0; int pathpos = 0;
bool variadic; bool variadic;
Oid va_elem_type; Oid va_elem_type;
List *defaults = NIL;
FuncCandidateList newResult; FuncCandidateList newResult;
/*
* Check if function has some parameter defaults if some
* parameters are missing.
*/
if (pronargs > nargs && expand_variadic)
{
bool isnull;
Datum proargdefaults;
char *str;
/* skip when not enough default expressions */
if (nargs + procform->pronargdefaults < pronargs)
continue;
proargdefaults = SysCacheGetAttr(PROCOID, proctup,
Anum_pg_proc_proargdefaults, &isnull);
Assert(!isnull);
str = TextDatumGetCString(proargdefaults);
defaults = (List *) stringToNode(str);
Assert(IsA(defaults, List));
/*
* If we don't have to use all default parameters, we skip
* some cells from the left.
*/
defaults = list_copy_tail(defaults, procform->pronargdefaults - pronargs + nargs);
pfree(str);
}
/* /*
* Check if function is variadic, and get variadic element type if so. * Check if function is variadic, and get variadic element type if so.
* If expand_variadic is false, we should just ignore variadic-ness. * If expand_variadic is false, we should just ignore variadic-ness.
*/ */
if (expand_variadic) if (pronargs <= nargs && expand_variadic)
{ {
va_elem_type = procform->provariadic; va_elem_type = procform->provariadic;
variadic = OidIsValid(va_elem_type); variadic = OidIsValid(va_elem_type);
@ -638,11 +675,16 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
variadic = false; variadic = false;
} }
Assert(!variadic || !defaults);
/* Ignore if it doesn't match requested argument count */ /* Ignore if it doesn't match requested argument count */
if (nargs >= 0 && if (nargs >= 0 &&
(variadic ? (pronargs > nargs) : (pronargs != nargs))) (variadic ? (pronargs > nargs) : (defaults ? (pronargs < nargs) : (pronargs != nargs))))
continue; continue;
Assert(!variadic || (pronargs <= nargs));
Assert(!defaults || (pronargs > nargs));
if (OidIsValid(namespaceId)) if (OidIsValid(namespaceId))
{ {
/* Consider only procs in specified namespace */ /* Consider only procs in specified namespace */
@ -681,6 +723,7 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
newResult->pathpos = pathpos; newResult->pathpos = pathpos;
newResult->oid = HeapTupleGetOid(proctup); newResult->oid = HeapTupleGetOid(proctup);
newResult->nargs = effective_nargs; newResult->nargs = effective_nargs;
newResult->argdefaults = defaults;
memcpy(newResult->args, procform->proargtypes.values, memcpy(newResult->args, procform->proargtypes.values,
pronargs * sizeof(Oid)); pronargs * sizeof(Oid));
if (variadic) if (variadic)
@ -695,6 +738,8 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
else else
newResult->nvargs = 0; newResult->nvargs = 0;
any_variadic = variadic || defaults;
/* /*
* Does it have the same arguments as something we already accepted? * Does it have the same arguments as something we already accepted?
* If so, decide which one to keep. We can skip this check for the * If so, decide which one to keep. We can skip this check for the
@ -704,6 +749,9 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
*/ */
if (any_variadic || !OidIsValid(namespaceId)) if (any_variadic || !OidIsValid(namespaceId))
{ {
if (defaults)
effective_nargs = nargs;
/* /*
* If we have an ordered list from SearchSysCacheList (the normal * If we have an ordered list from SearchSysCacheList (the normal
* case), then any conflicting proc must immediately adjoin this * case), then any conflicting proc must immediately adjoin this
@ -733,11 +781,21 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
prevResult; prevResult;
prevResult = prevResult->next) prevResult = prevResult->next)
{ {
if (effective_nargs == prevResult->nargs && if (!defaults)
memcmp(newResult->args, {
prevResult->args, if (effective_nargs == prevResult->nargs &&
effective_nargs * sizeof(Oid)) == 0) memcmp(newResult->args,
prevResult->args,
effective_nargs * sizeof(Oid)) == 0)
break;
}
else
{
if (memcmp(newResult->args,
prevResult->args,
effective_nargs * sizeof(Oid)) == 0)
break; break;
}
} }
} }
if (prevResult) if (prevResult)
@ -777,6 +835,20 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
pfree(newResult); pfree(newResult);
continue; /* keep previous result */ continue; /* keep previous result */
} }
if (defaults)
{
if (prevResult->argdefaults != NIL)
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
errmsg("functions with parameter defaults %s and %s are ambiguous",
func_signature_string(names, pronargs, procform->proargtypes.values),
func_signature_string(names, prevResult->nargs, prevResult->args))));
/* else, previous result didn't have defaults */
pfree(newResult);
continue; /* keep previous result */
}
/* non-variadic can replace a previous variadic */ /* non-variadic can replace a previous variadic */
Assert(prevResult->nvargs > 0); Assert(prevResult->nvargs > 0);
} }
@ -784,6 +856,7 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
prevResult->pathpos = pathpos; prevResult->pathpos = pathpos;
prevResult->oid = newResult->oid; prevResult->oid = newResult->oid;
prevResult->nvargs = newResult->nvargs; prevResult->nvargs = newResult->nvargs;
prevResult->argdefaults = newResult->argdefaults;
pfree(newResult); pfree(newResult);
continue; /* args are same, of course */ continue; /* args are same, of course */
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.97 2008/11/14 19:47:50 tgl Exp $ * $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.98 2008/12/04 17:51:26 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -229,7 +229,8 @@ AggregateCreate(const char *aggName,
PointerGetDatum(NULL), /* parameterNames */ PointerGetDatum(NULL), /* parameterNames */
PointerGetDatum(NULL), /* proconfig */ PointerGetDatum(NULL), /* proconfig */
1, /* procost */ 1, /* procost */
0); /* prorows */ 0, /* prorows */
NULL); /* parameterDefaults */
/* /*
* Okay to create the pg_aggregate entry. * Okay to create the pg_aggregate entry.
@ -321,7 +322,7 @@ lookup_agg_function(List *fnName,
*/ */
fdresult = func_get_detail(fnName, NIL, nargs, input_types, false, fdresult = func_get_detail(fnName, NIL, nargs, input_types, false,
&fnOid, rettype, &retset, &nvargs, &fnOid, rettype, &retset, &nvargs,
&true_oid_array); &true_oid_array, NULL);
/* only valid case is a normal function not returning a set */ /* only valid case is a normal function not returning a set */
if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid)) if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.154 2008/11/02 01:45:27 tgl Exp $ * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.155 2008/12/04 17:51:26 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -75,7 +75,8 @@ ProcedureCreate(const char *procedureName,
Datum parameterNames, Datum parameterNames,
Datum proconfig, Datum proconfig,
float4 procost, float4 procost,
float4 prorows) float4 prorows,
List *parameterDefaults)
{ {
Oid retval; Oid retval;
int parameterCount; int parameterCount;
@ -295,6 +296,7 @@ ProcedureCreate(const char *procedureName,
values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet); values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet);
values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility); values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility);
values[Anum_pg_proc_pronargs - 1] = UInt16GetDatum(parameterCount); values[Anum_pg_proc_pronargs - 1] = UInt16GetDatum(parameterCount);
values[Anum_pg_proc_pronargdefaults - 1] = UInt16GetDatum(list_length(parameterDefaults));
values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType); values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType);
values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes); values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes);
if (allParameterTypes != PointerGetDatum(NULL)) if (allParameterTypes != PointerGetDatum(NULL))
@ -309,6 +311,13 @@ ProcedureCreate(const char *procedureName,
values[Anum_pg_proc_proargnames - 1] = parameterNames; values[Anum_pg_proc_proargnames - 1] = parameterNames;
else else
nulls[Anum_pg_proc_proargnames - 1] = true; nulls[Anum_pg_proc_proargnames - 1] = true;
if (parameterDefaults != PointerGetDatum(NULL))
{
Assert(list_length(parameterDefaults) > 0);
values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodeToString(parameterDefaults));
}
else
nulls[Anum_pg_proc_proargdefaults - 1] = true;
values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc); values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc);
if (probin) if (probin)
values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin); values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin);

View File

@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.101 2008/11/02 01:45:27 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.102 2008/12/04 17:51:26 petere Exp $
* *
* DESCRIPTION * DESCRIPTION
* These routines take the parse tree and pick out the * These routines take the parse tree and pick out the
@ -49,8 +49,10 @@
#include "commands/proclang.h" #include "commands/proclang.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "parser/parse_coerce.h" #include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h" #include "parser/parse_func.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "parser/parse_utilcmd.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
@ -164,7 +166,9 @@ examine_parameter_list(List *parameters, Oid languageOid,
ArrayType **allParameterTypes, ArrayType **allParameterTypes,
ArrayType **parameterModes, ArrayType **parameterModes,
ArrayType **parameterNames, ArrayType **parameterNames,
Oid *requiredResultType) List **parameterDefaults,
Oid *requiredResultType,
const char *queryString)
{ {
int parameterCount = list_length(parameters); int parameterCount = list_length(parameters);
Oid *inTypes; Oid *inTypes;
@ -177,6 +181,8 @@ examine_parameter_list(List *parameters, Oid languageOid,
bool have_names = false; bool have_names = false;
ListCell *x; ListCell *x;
int i; int i;
bool have_defaults = false;
ParseState *pstate;
*requiredResultType = InvalidOid; /* default result */ *requiredResultType = InvalidOid; /* default result */
@ -184,6 +190,10 @@ examine_parameter_list(List *parameters, Oid languageOid,
allTypes = (Datum *) palloc(parameterCount * sizeof(Datum)); allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
paramModes = (Datum *) palloc(parameterCount * sizeof(Datum)); paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum)); paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
*parameterDefaults = NIL;
pstate = make_parsestate(NULL);
pstate->p_sourcetext = queryString;
/* Scan the list and extract data into work arrays */ /* Scan the list and extract data into work arrays */
i = 0; i = 0;
@ -276,9 +286,33 @@ examine_parameter_list(List *parameters, Oid languageOid,
have_names = true; have_names = true;
} }
if (fp->defexpr)
{
if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_INOUT)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("only IN and INOUT parameters can have default values")));
*parameterDefaults = lappend(*parameterDefaults,
coerce_to_specific_type(NULL,
transformExpr(pstate, fp->defexpr),
toid,
"DEFAULT"));
have_defaults = true;
}
else
{
if (have_defaults)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("parameter without default value specified after parameter with default value")));
}
i++; i++;
} }
free_parsestate(pstate);
/* Now construct the proper outputs as needed */ /* Now construct the proper outputs as needed */
*parameterTypes = buildoidvector(inTypes, inCount); *parameterTypes = buildoidvector(inTypes, inCount);
@ -653,7 +687,7 @@ interpret_AS_clause(Oid languageOid, const char *languageName,
* Execute a CREATE FUNCTION utility statement. * Execute a CREATE FUNCTION utility statement.
*/ */
void void
CreateFunction(CreateFunctionStmt *stmt) CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
{ {
char *probin_str; char *probin_str;
char *prosrc_str; char *prosrc_str;
@ -680,6 +714,7 @@ CreateFunction(CreateFunctionStmt *stmt)
HeapTuple languageTuple; HeapTuple languageTuple;
Form_pg_language languageStruct; Form_pg_language languageStruct;
List *as_clause; List *as_clause;
List *defaults = NULL;
/* Convert list of names to a name and namespace */ /* Convert list of names to a name and namespace */
namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname, namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
@ -753,7 +788,9 @@ CreateFunction(CreateFunctionStmt *stmt)
&allParameterTypes, &allParameterTypes,
&parameterModes, &parameterModes,
&parameterNames, &parameterNames,
&requiredResultType); &defaults,
&requiredResultType,
queryString);
if (stmt->returnType) if (stmt->returnType)
{ {
@ -836,7 +873,8 @@ CreateFunction(CreateFunctionStmt *stmt)
PointerGetDatum(parameterNames), PointerGetDatum(parameterNames),
PointerGetDatum(proconfig), PointerGetDatum(proconfig),
procost, procost,
prorows); prorows,
defaults);
} }

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.80 2008/11/02 01:45:27 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.81 2008/12/04 17:51:26 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -149,7 +149,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
PointerGetDatum(NULL), PointerGetDatum(NULL),
PointerGetDatum(NULL), PointerGetDatum(NULL),
1, 1,
0); 0,
NULL);
} }
/* /*
@ -182,7 +183,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
PointerGetDatum(NULL), PointerGetDatum(NULL),
PointerGetDatum(NULL), PointerGetDatum(NULL),
1, 1,
0); 0,
NULL);
} }
} }
else else

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.414 2008/12/04 11:42:23 heikki Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.415 2008/12/04 17:51:26 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -2448,6 +2448,7 @@ _copyFunctionParameter(FunctionParameter *from)
COPY_STRING_FIELD(name); COPY_STRING_FIELD(name);
COPY_NODE_FIELD(argType); COPY_NODE_FIELD(argType);
COPY_SCALAR_FIELD(mode); COPY_SCALAR_FIELD(mode);
COPY_NODE_FIELD(defexpr);
return newnode; return newnode;
} }

View File

@ -22,7 +22,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.339 2008/12/04 11:42:24 heikki Exp $ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.340 2008/12/04 17:51:26 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1165,6 +1165,7 @@ _equalFunctionParameter(FunctionParameter *a, FunctionParameter *b)
COMPARE_STRING_FIELD(name); COMPARE_STRING_FIELD(name);
COMPARE_NODE_FIELD(argType); COMPARE_NODE_FIELD(argType);
COMPARE_SCALAR_FIELD(mode); COMPARE_SCALAR_FIELD(mode);
COMPARE_NODE_FIELD(defexpr);
return true; return true;
} }

View File

@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.642 2008/12/04 11:42:24 heikki Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.643 2008/12/04 17:51:26 petere Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
@ -255,6 +255,7 @@ static TypeName *TableFuncTypeName(List *columns);
%type <list> stmtblock stmtmulti %type <list> stmtblock stmtmulti
OptTableElementList TableElementList OptInherit definition OptTableElementList TableElementList OptInherit definition
OptWith opt_distinct opt_definition func_args func_args_list OptWith opt_distinct opt_definition func_args func_args_list
func_args_with_defaults func_args_with_defaults_list
func_as createfunc_opt_list alterfunc_opt_list func_as createfunc_opt_list alterfunc_opt_list
aggr_args old_aggr_definition old_aggr_list aggr_args old_aggr_definition old_aggr_list
oper_argtypes RuleActionList RuleActionMulti oper_argtypes RuleActionList RuleActionMulti
@ -278,7 +279,7 @@ static TypeName *TableFuncTypeName(List *columns);
%type <into> into_clause create_as_target %type <into> into_clause create_as_target
%type <defelt> createfunc_opt_item common_func_opt_item %type <defelt> createfunc_opt_item common_func_opt_item
%type <fun_param> func_arg table_func_column %type <fun_param> func_arg func_arg_with_default table_func_column
%type <fun_param_mode> arg_class %type <fun_param_mode> arg_class
%type <typnam> func_return func_type %type <typnam> func_return func_type
@ -4170,7 +4171,7 @@ opt_nulls_order: NULLS_FIRST { $$ = SORTBY_NULLS_FIRST; }
*****************************************************************************/ *****************************************************************************/
CreateFunctionStmt: CreateFunctionStmt:
CREATE opt_or_replace FUNCTION func_name func_args CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
RETURNS func_return createfunc_opt_list opt_definition RETURNS func_return createfunc_opt_list opt_definition
{ {
CreateFunctionStmt *n = makeNode(CreateFunctionStmt); CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
@ -4182,7 +4183,7 @@ CreateFunctionStmt:
n->withClause = $9; n->withClause = $9;
$$ = (Node *)n; $$ = (Node *)n;
} }
| CREATE opt_or_replace FUNCTION func_name func_args | CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
RETURNS TABLE '(' table_func_column_list ')' createfunc_opt_list opt_definition RETURNS TABLE '(' table_func_column_list ')' createfunc_opt_list opt_definition
{ {
CreateFunctionStmt *n = makeNode(CreateFunctionStmt); CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
@ -4195,7 +4196,7 @@ CreateFunctionStmt:
n->withClause = $12; n->withClause = $12;
$$ = (Node *)n; $$ = (Node *)n;
} }
| CREATE opt_or_replace FUNCTION func_name func_args | CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
createfunc_opt_list opt_definition createfunc_opt_list opt_definition
{ {
CreateFunctionStmt *n = makeNode(CreateFunctionStmt); CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
@ -4223,6 +4224,21 @@ func_args_list:
| func_args_list ',' func_arg { $$ = lappend($1, $3); } | func_args_list ',' func_arg { $$ = lappend($1, $3); }
; ;
/*
* func_args_with_defaults is separate because we only want to accept
* defaults in CREATE FUNCTION, not in ALTER etc.
*/
func_args_with_defaults:
'(' func_args_with_defaults_list ')' { $$ = $2; }
| '(' ')' { $$ = NIL; }
;
func_args_with_defaults_list:
func_arg_with_default { $$ = list_make1( $1); }
| func_args_with_defaults_list ',' func_arg_with_default { $$ = lappend($1, $3); }
;
/* /*
* The style with arg_class first is SQL99 standard, but Oracle puts * The style with arg_class first is SQL99 standard, but Oracle puts
* param_name first; accept both since it's likely people will try both * param_name first; accept both since it's likely people will try both
@ -4240,6 +4256,7 @@ func_arg:
n->name = $2; n->name = $2;
n->argType = $3; n->argType = $3;
n->mode = $1; n->mode = $1;
n->defexpr = NULL;
$$ = n; $$ = n;
} }
| param_name arg_class func_type | param_name arg_class func_type
@ -4248,6 +4265,7 @@ func_arg:
n->name = $1; n->name = $1;
n->argType = $3; n->argType = $3;
n->mode = $2; n->mode = $2;
n->defexpr = NULL;
$$ = n; $$ = n;
} }
| param_name func_type | param_name func_type
@ -4256,6 +4274,7 @@ func_arg:
n->name = $1; n->name = $1;
n->argType = $2; n->argType = $2;
n->mode = FUNC_PARAM_IN; n->mode = FUNC_PARAM_IN;
n->defexpr = NULL;
$$ = n; $$ = n;
} }
| arg_class func_type | arg_class func_type
@ -4264,6 +4283,7 @@ func_arg:
n->name = NULL; n->name = NULL;
n->argType = $2; n->argType = $2;
n->mode = $1; n->mode = $1;
n->defexpr = NULL;
$$ = n; $$ = n;
} }
| func_type | func_type
@ -4272,6 +4292,7 @@ func_arg:
n->name = NULL; n->name = NULL;
n->argType = $1; n->argType = $1;
n->mode = FUNC_PARAM_IN; n->mode = FUNC_PARAM_IN;
n->defexpr = NULL;
$$ = n; $$ = n;
} }
; ;
@ -4322,6 +4343,23 @@ func_type: Typename { $$ = $1; }
} }
; ;
func_arg_with_default:
func_arg
{
$$ = $1;
}
| func_arg DEFAULT a_expr
{
$$ = $1;
$$->defexpr = $3;
}
| func_arg '=' a_expr
{
$$ = $1;
$$->defexpr = $3;
}
;
createfunc_opt_list: createfunc_opt_list:
/* Must be at least one to prevent conflict */ /* Must be at least one to prevent conflict */

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.207 2008/09/01 20:42:44 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.208 2008/12/04 17:51:26 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -77,6 +77,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
bool retset; bool retset;
int nvargs; int nvargs;
FuncDetailCode fdresult; FuncDetailCode fdresult;
List *argdefaults;
/* /*
* Most of the rest of the parser just assumes that functions do not have * Most of the rest of the parser just assumes that functions do not have
@ -164,7 +165,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
fdresult = func_get_detail(funcname, fargs, nargs, actual_arg_types, fdresult = func_get_detail(funcname, fargs, nargs, actual_arg_types,
!func_variadic, !func_variadic,
&funcid, &rettype, &retset, &nvargs, &funcid, &rettype, &retset, &nvargs,
&declared_arg_types); &declared_arg_types, &argdefaults);
if (fdresult == FUNCDETAIL_COERCION) if (fdresult == FUNCDETAIL_COERCION)
{ {
/* /*
@ -234,6 +235,21 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
parser_errposition(pstate, location))); parser_errposition(pstate, location)));
} }
/* add stored expressions as called values for arguments with defaults */
if (argdefaults)
{
ListCell *lc;
foreach(lc, argdefaults)
{
Node *expr = (Node *) lfirst(lc);
fargs = lappend(fargs, expr);
actual_arg_types[nargs++] = exprType(expr);
}
}
/* /*
* enforce consistency with polymorphic argument and return types, * enforce consistency with polymorphic argument and return types,
* possibly adjusting return type or declared_arg_types (which will be * possibly adjusting return type or declared_arg_types (which will be
@ -729,7 +745,8 @@ func_get_detail(List *funcname,
Oid *rettype, /* return value */ Oid *rettype, /* return value */
bool *retset, /* return value */ bool *retset, /* return value */
int *nvargs, /* return value */ int *nvargs, /* return value */
Oid **true_typeids) /* return value */ Oid **true_typeids, /* return value */
List **argdefaults) /* return value */
{ {
FuncCandidateList raw_candidates; FuncCandidateList raw_candidates;
FuncCandidateList best_candidate; FuncCandidateList best_candidate;
@ -870,6 +887,8 @@ func_get_detail(List *funcname,
*funcid = best_candidate->oid; *funcid = best_candidate->oid;
*nvargs = best_candidate->nvargs; *nvargs = best_candidate->nvargs;
*true_typeids = best_candidate->args; *true_typeids = best_candidate->args;
if (argdefaults)
*argdefaults = best_candidate->argdefaults;
ftup = SearchSysCache(PROCOID, ftup = SearchSysCache(PROCOID,
ObjectIdGetDatum(best_candidate->oid), ObjectIdGetDatum(best_candidate->oid),

View File

@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.301 2008/11/07 18:25:06 tgl Exp $ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.302 2008/12/04 17:51:26 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -700,7 +700,7 @@ ProcessUtility(Node *parsetree,
break; break;
case T_CreateFunctionStmt: /* CREATE FUNCTION */ case T_CreateFunctionStmt: /* CREATE FUNCTION */
CreateFunction((CreateFunctionStmt *) parsetree); CreateFunction((CreateFunctionStmt *) parsetree, queryString);
break; break;
case T_AlterFunctionStmt: /* ALTER FUNCTION */ case T_AlterFunctionStmt: /* ALTER FUNCTION */

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.287 2008/10/06 20:29:38 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.288 2008/12/04 17:51:27 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -141,7 +141,8 @@ static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
static char *pg_get_expr_worker(text *expr, Oid relid, char *relname, static char *pg_get_expr_worker(text *expr, Oid relid, char *relname,
int prettyFlags); int prettyFlags);
static int print_function_arguments(StringInfo buf, HeapTuple proctup, static int print_function_arguments(StringInfo buf, HeapTuple proctup,
bool print_table_args); bool print_table_args,
bool full);
static void print_function_rettype(StringInfo buf, HeapTuple proctup); static void print_function_rettype(StringInfo buf, HeapTuple proctup);
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
int prettyFlags); int prettyFlags);
@ -1449,7 +1450,7 @@ pg_get_functiondef(PG_FUNCTION_ARGS)
nsp = get_namespace_name(proc->pronamespace); nsp = get_namespace_name(proc->pronamespace);
appendStringInfo(&buf, "CREATE OR REPLACE FUNCTION %s(", appendStringInfo(&buf, "CREATE OR REPLACE FUNCTION %s(",
quote_qualified_identifier(nsp, name)); quote_qualified_identifier(nsp, name));
(void) print_function_arguments(&buf, proctup, false); (void) print_function_arguments(&buf, proctup, false, true);
appendStringInfoString(&buf, ")\n RETURNS "); appendStringInfoString(&buf, ")\n RETURNS ");
print_function_rettype(&buf, proctup); print_function_rettype(&buf, proctup);
appendStringInfo(&buf, "\n LANGUAGE %s\n", appendStringInfo(&buf, "\n LANGUAGE %s\n",
@ -1598,13 +1599,43 @@ pg_get_function_arguments(PG_FUNCTION_ARGS)
if (!HeapTupleIsValid(proctup)) if (!HeapTupleIsValid(proctup))
elog(ERROR, "cache lookup failed for function %u", funcid); elog(ERROR, "cache lookup failed for function %u", funcid);
(void) print_function_arguments(&buf, proctup, false); (void) print_function_arguments(&buf, proctup, false, true);
ReleaseSysCache(proctup); ReleaseSysCache(proctup);
PG_RETURN_TEXT_P(string_to_text(buf.data)); PG_RETURN_TEXT_P(string_to_text(buf.data));
} }
/*
* pg_get_function_identity_arguments
* Get a formatted list of arguments for a function.
* This is everything that would go between the parentheses in
* ALTER FUNCTION, etc. skip names and defaults/
*/
Datum
pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
{
Oid funcid = PG_GETARG_OID(0);
StringInfoData buf;
HeapTuple proctup;
initStringInfo(&buf);
proctup = SearchSysCache(PROCOID,
ObjectIdGetDatum(funcid),
0, 0, 0);
if (!HeapTupleIsValid(proctup))
elog(ERROR, "cache lookup failed for function %u", funcid);
(void) print_function_arguments(&buf, proctup, false, false);
ReleaseSysCache(proctup);
PG_RETURN_TEXT_P(string_to_text(buf.data));
}
/* /*
* pg_get_function_result * pg_get_function_result
* Get a nicely-formatted version of the result type of a function. * Get a nicely-formatted version of the result type of a function.
@ -1649,7 +1680,7 @@ print_function_rettype(StringInfo buf, HeapTuple proctup)
{ {
/* It might be a table function; try to print the arguments */ /* It might be a table function; try to print the arguments */
appendStringInfoString(&rbuf, "TABLE("); appendStringInfoString(&rbuf, "TABLE(");
ntabargs = print_function_arguments(&rbuf, proctup, true); ntabargs = print_function_arguments(&rbuf, proctup, true, true);
if (ntabargs > 0) if (ntabargs > 0)
appendStringInfoString(&rbuf, ")"); appendStringInfoString(&rbuf, ")");
else else
@ -1672,10 +1703,12 @@ print_function_rettype(StringInfo buf, HeapTuple proctup)
* append the desired subset of arguments to buf. We print only TABLE * append the desired subset of arguments to buf. We print only TABLE
* arguments when print_table_args is true, and all the others when it's false. * arguments when print_table_args is true, and all the others when it's false.
* Function return value is the number of arguments printed. * Function return value is the number of arguments printed.
* When full is false, then don't print argument names and argument defaults.
*/ */
static int static int
print_function_arguments(StringInfo buf, HeapTuple proctup, print_function_arguments(StringInfo buf, HeapTuple proctup,
bool print_table_args) bool print_table_args,
bool full)
{ {
int numargs; int numargs;
Oid *argtypes; Oid *argtypes;
@ -1683,10 +1716,37 @@ print_function_arguments(StringInfo buf, HeapTuple proctup,
char *argmodes; char *argmodes;
int argsprinted; int argsprinted;
int i; int i;
Datum proargdefaults;
List *argdefaults;
int nargdefaults;
bool isnull;
List *dcontext = NIL;
numargs = get_func_arg_info(proctup, numargs = get_func_arg_info(proctup,
&argtypes, &argnames, &argmodes); &argtypes, &argnames, &argmodes);
proargdefaults = SysCacheGetAttr(PROCOID, proctup,
Anum_pg_proc_proargdefaults, &isnull);
if (!isnull)
{
char *str;
str = TextDatumGetCString(proargdefaults);
argdefaults = (List *) stringToNode(str);
Assert(IsA(argdefaults, List));
nargdefaults = list_length(argdefaults);
/* we will need deparse context */
//dcontext = deparse_context_for("", InvalidOid);
dcontext = NULL;
pfree(str);
}
else
{
argdefaults = NIL;
nargdefaults = 0;
}
argsprinted = 0; argsprinted = 0;
for (i = 0; i < numargs; i++) for (i = 0; i < numargs; i++)
{ {
@ -1723,9 +1783,19 @@ print_function_arguments(StringInfo buf, HeapTuple proctup,
if (argsprinted) if (argsprinted)
appendStringInfoString(buf, ", "); appendStringInfoString(buf, ", ");
appendStringInfoString(buf, modename); appendStringInfoString(buf, modename);
if (argname && argname[0]) if (argname && argname[0] && full)
appendStringInfo(buf, "%s ", argname); appendStringInfo(buf, "%s ", argname);
appendStringInfoString(buf, format_type_be(argtype)); appendStringInfoString(buf, format_type_be(argtype));
/* search given default expression, expect less numargs */
if (nargdefaults > 0 && i >= (numargs - nargdefaults) && full)
{
Node *expr;
expr = (Node *) list_nth(argdefaults, i - (numargs - nargdefaults));
appendStringInfo(buf, " DEFAULT %s", deparse_expression(expr, dcontext, false, false));
}
argsprinted++; argsprinted++;
} }
@ -6002,7 +6072,7 @@ generate_function_name(Oid funcid, int nargs, Oid *argtypes,
p_result = func_get_detail(list_make1(makeString(proname)), p_result = func_get_detail(list_make1(makeString(proname)),
NIL, nargs, argtypes, false, NIL, nargs, argtypes, false,
&p_funcid, &p_rettype, &p_funcid, &p_rettype,
&p_retset, &p_nvargs, &p_true_typeids); &p_retset, &p_nvargs, &p_true_typeids, NULL);
if ((p_result == FUNCDETAIL_NORMAL || p_result == FUNCDETAIL_AGGREGATE) && if ((p_result == FUNCDETAIL_NORMAL || p_result == FUNCDETAIL_AGGREGATE) &&
p_funcid == funcid) p_funcid == funcid)
nspname = NULL; nspname = NULL;

View File

@ -12,7 +12,7 @@
* by PostgreSQL * by PostgreSQL
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.505 2008/11/09 21:24:32 tgl Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.506 2008/12/04 17:51:27 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -6733,13 +6733,15 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
PQExpBuffer delqry; PQExpBuffer delqry;
PQExpBuffer asPart; PQExpBuffer asPart;
PGresult *res; PGresult *res;
char *funcsig; char *funcsig; /* identity signature */
char *funcfullsig; /* full signature */
char *funcsig_tag; char *funcsig_tag;
int ntups; int ntups;
char *proretset; char *proretset;
char *prosrc; char *prosrc;
char *probin; char *probin;
char *funcargs; char *funcargs;
char *funciargs;
char *funcresult; char *funcresult;
char *proallargtypes; char *proallargtypes;
char *proargmodes; char *proargmodes;
@ -6782,6 +6784,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
appendPQExpBuffer(query, appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, " "SELECT proretset, prosrc, probin, "
"pg_catalog.pg_get_function_arguments(oid) as funcargs, " "pg_catalog.pg_get_function_arguments(oid) as funcargs, "
"pg_catalog.pg_get_function_identity_arguments(oid) as funciargs, "
"pg_catalog.pg_get_function_result(oid) as funcresult, " "pg_catalog.pg_get_function_result(oid) as funcresult, "
"provolatile, proisstrict, prosecdef, " "provolatile, proisstrict, prosecdef, "
"proconfig, procost, prorows, " "proconfig, procost, prorows, "
@ -6893,6 +6896,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
if (g_fout->remoteVersion >= 80400) if (g_fout->remoteVersion >= 80400)
{ {
funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs")); funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult")); funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
proallargtypes = proargmodes = proargnames = NULL; proallargtypes = proargmodes = proargnames = NULL;
} }
@ -6901,7 +6905,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes")); proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes")); proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames")); proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
funcargs = funcresult = NULL; funcargs = funciargs = funcresult = NULL;
} }
provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile")); provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict")); proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
@ -7007,11 +7011,19 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
} }
} }
if (funcargs) /* funcargs and funciargs are supported from 8.4 */
funcsig = format_function_arguments(finfo, funcargs); if (funciargs)
{
funcsig = format_function_arguments(finfo, funciargs);
funcfullsig = format_function_arguments(finfo, funcargs);
}
else else
{
funcsig = format_function_arguments_old(finfo, nallargs, allargtypes, funcsig = format_function_arguments_old(finfo, nallargs, allargtypes,
argmodes, argnames); argmodes, argnames);
funcfullsig = funcsig;
}
funcsig_tag = format_function_signature(finfo, false); funcsig_tag = format_function_signature(finfo, false);
/* /*
@ -7021,7 +7033,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
fmtId(finfo->dobj.namespace->dobj.name), fmtId(finfo->dobj.namespace->dobj.name),
funcsig); funcsig);
appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcsig); appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
if (funcresult) if (funcresult)
appendPQExpBuffer(q, "RETURNS %s", funcresult); appendPQExpBuffer(q, "RETURNS %s", funcresult);
else else

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.510 2008/12/03 13:28:53 heikki Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.511 2008/12/04 17:51:27 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200812031 #define CATALOG_VERSION_NO 200812041
#endif #endif

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.55 2008/07/16 01:30:23 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.56 2008/12/04 17:51:27 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -30,6 +30,7 @@ typedef struct _FuncCandidateList
Oid oid; /* the function or operator's OID */ Oid oid; /* the function or operator's OID */
int nargs; /* number of arg types returned */ int nargs; /* number of arg types returned */
int nvargs; /* number of args to become variadic array */ int nvargs; /* number of args to become variadic array */
List *argdefaults; /* list of parameter defaults */
Oid args[1]; /* arg types --- VARIABLE LENGTH ARRAY */ Oid args[1]; /* arg types --- VARIABLE LENGTH ARRAY */
} *FuncCandidateList; /* VARIABLE LENGTH STRUCT */ } *FuncCandidateList; /* VARIABLE LENGTH STRUCT */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.141 2008/11/09 21:24:33 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.142 2008/12/04 17:51:27 petere Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -300,15 +300,17 @@ DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
{ 1255, {"proretset"}, 16, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ { 1255, {"proretset"}, 16, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1255, {"provolatile"}, 18, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ { 1255, {"provolatile"}, 18, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1255, {"pronargs"}, 21, -1, 2, 13, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ { 1255, {"pronargs"}, 21, -1, 2, 13, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
{ 1255, {"prorettype"}, 26, -1, 4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ { 1255, {"pronargdefaults"}, 21, -1, 2, 14, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
{ 1255, {"proargtypes"}, 30, -1, -1, 15, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 1255, {"prorettype"}, 26, -1, 4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1255, {"proallargtypes"}, 1028, -1, -1, 16, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ { 1255, {"proargtypes"}, 30, -1, -1, 16, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
{ 1255, {"proargmodes"}, 1002, -1, -1, 17, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ { 1255, {"proallargtypes"}, 1028, -1, -1, 17, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"proargnames"}, 1009, -1, -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ { 1255, {"proargmodes"}, 1002, -1, -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"prosrc"}, 25, -1, -1, 19, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ { 1255, {"proargnames"}, 1009, -1, -1, 19, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"probin"}, 17, -1, -1, 20, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ { 1255, {"proargdefaults"}, 25, -1, -1, 20, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"proconfig"}, 1009, -1, -1, 21, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ { 1255, {"prosrc"}, 25, -1, -1, 21, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"proacl"}, 1034, -1, -1, 22, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 } { 1255, {"probin"}, 17, -1, -1, 22, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"proconfig"}, 1009, -1, -1, 23, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"proacl"}, 1034, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
DATA(insert ( 1255 proname 19 -1 NAMEDATALEN 1 0 -1 -1 f p c t f f t 0)); DATA(insert ( 1255 proname 19 -1 NAMEDATALEN 1 0 -1 -1 f p c t f f t 0));
DATA(insert ( 1255 pronamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1255 pronamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0));
@ -323,15 +325,17 @@ DATA(insert ( 1255 proisstrict 16 -1 1 10 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1255 proretset 16 -1 1 11 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1255 proretset 16 -1 1 11 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1255 provolatile 18 -1 1 12 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1255 provolatile 18 -1 1 12 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1255 pronargs 21 -1 2 13 0 -1 -1 t p s t f f t 0)); DATA(insert ( 1255 pronargs 21 -1 2 13 0 -1 -1 t p s t f f t 0));
DATA(insert ( 1255 prorettype 26 -1 4 14 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1255 pronargdefaults 21 -1 2 14 0 -1 -1 t p s t f f t 0));
DATA(insert ( 1255 proargtypes 30 -1 -1 15 1 -1 -1 f p i t f f t 0)); DATA(insert ( 1255 prorettype 26 -1 4 15 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1255 proallargtypes 1028 -1 -1 16 1 -1 -1 f x i f f f t 0)); DATA(insert ( 1255 proargtypes 30 -1 -1 16 1 -1 -1 f p i t f f t 0));
DATA(insert ( 1255 proargmodes 1002 -1 -1 17 1 -1 -1 f x i f f f t 0)); DATA(insert ( 1255 proallargtypes 1028 -1 -1 17 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 proargnames 1009 -1 -1 18 1 -1 -1 f x i f f f t 0)); DATA(insert ( 1255 proargmodes 1002 -1 -1 18 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 prosrc 25 -1 -1 19 0 -1 -1 f x i f f f t 0)); DATA(insert ( 1255 proargnames 1009 -1 -1 19 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 probin 17 -1 -1 20 0 -1 -1 f x i f f f t 0)); DATA(insert ( 1255 proargdefaults 25 -1 -1 20 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 proconfig 1009 -1 -1 21 1 -1 -1 f x i f f f t 0)); DATA(insert ( 1255 prosrc 25 -1 -1 21 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 proacl 1034 -1 -1 22 1 -1 -1 f x i f f f t 0)); DATA(insert ( 1255 probin 17 -1 -1 22 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 proconfig 1009 -1 -1 23 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 proacl 1034 -1 -1 24 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0));
DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0));

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.108 2008/11/09 21:24:33 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.109 2008/12/04 17:51:27 petere Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -125,7 +125,7 @@ DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 28 0 t
DESCR(""); DESCR("");
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 f f f f f 3 _null_ _null_ )); DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 f f f f f 3 _null_ _null_ ));
DESCR(""); DESCR("");
DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 22 0 t f f f f 3 _null_ _null_ )); DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 24 0 t f f f f 3 _null_ _null_ ));
DESCR(""); DESCR("");
DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 24 0 t f f f f 3 _null_ _null_ )); DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 24 0 t f f f f 3 _null_ _null_ ));
DESCR(""); DESCR("");

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_proc_fn.h,v 1.1 2008/03/27 03:57:34 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_proc_fn.h,v 1.2 2008/12/04 17:51:27 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -33,7 +33,8 @@ extern Oid ProcedureCreate(const char *procedureName,
Datum parameterNames, Datum parameterNames,
Datum proconfig, Datum proconfig,
float4 procost, float4 procost,
float4 prorows); float4 prorows,
List *parameterDefaults);
extern bool function_parse_error_transpose(const char *prosrc); extern bool function_parse_error_transpose(const char *prosrc);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.89 2008/06/14 18:04:34 tgl Exp $ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.90 2008/12/04 17:51:27 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -45,7 +45,7 @@ extern char *ChooseRelationName(const char *name1, const char *name2,
extern Oid GetDefaultOpClass(Oid type_id, Oid am_id); extern Oid GetDefaultOpClass(Oid type_id, Oid am_id);
/* commands/functioncmds.c */ /* commands/functioncmds.c */
extern void CreateFunction(CreateFunctionStmt *stmt); extern void CreateFunction(CreateFunctionStmt *stmt, const char *queryString);
extern void RemoveFunction(RemoveFuncStmt *stmt); extern void RemoveFunction(RemoveFuncStmt *stmt);
extern void RemoveFunctionById(Oid funcOid); extern void RemoveFunctionById(Oid funcOid);
extern void SetFunctionReturnType(Oid funcOid, Oid newRetType); extern void SetFunctionReturnType(Oid funcOid, Oid newRetType);

View File

@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.380 2008/12/04 11:42:24 heikki Exp $ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.381 2008/12/04 17:51:27 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1686,6 +1686,7 @@ typedef struct FunctionParameter
char *name; /* parameter name, or NULL if not given */ char *name; /* parameter name, or NULL if not given */
TypeName *argType; /* TypeName for parameter type */ TypeName *argType; /* TypeName for parameter type */
FunctionParameterMode mode; /* IN/OUT/INOUT */ FunctionParameterMode mode; /* IN/OUT/INOUT */
Node *defexpr; /* Default expression, or NULL if not given */
} FunctionParameter; } FunctionParameter;
typedef struct AlterFunctionStmt typedef struct AlterFunctionStmt

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/parser/parse_func.h,v 1.60 2008/07/16 01:30:23 tgl Exp $ * $PostgreSQL: pgsql/src/include/parser/parse_func.h,v 1.61 2008/12/04 17:51:27 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -49,7 +49,8 @@ extern Node *ParseFuncOrColumn(ParseState *pstate,
extern FuncDetailCode func_get_detail(List *funcname, List *fargs, extern FuncDetailCode func_get_detail(List *funcname, List *fargs,
int nargs, Oid *argtypes, bool expand_variadic, int nargs, Oid *argtypes, bool expand_variadic,
Oid *funcid, Oid *rettype, Oid *funcid, Oid *rettype,
bool *retset, int *nvargs, Oid **true_typeids); bool *retset, int *nvargs, Oid **true_typeids,
List **argdefaults);
extern int func_match_argtypes(int nargs, extern int func_match_argtypes(int nargs,
Oid *input_typeids, Oid *input_typeids,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.326 2008/11/03 20:17:20 adunstan Exp $ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.327 2008/12/04 17:51:28 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -553,6 +553,7 @@ extern Datum pg_get_userbyid(PG_FUNCTION_ARGS);
extern Datum pg_get_serial_sequence(PG_FUNCTION_ARGS); extern Datum pg_get_serial_sequence(PG_FUNCTION_ARGS);
extern Datum pg_get_functiondef(PG_FUNCTION_ARGS); extern Datum pg_get_functiondef(PG_FUNCTION_ARGS);
extern Datum pg_get_function_arguments(PG_FUNCTION_ARGS); extern Datum pg_get_function_arguments(PG_FUNCTION_ARGS);
extern Datum pg_get_function_identity_arguments(PG_FUNCTION_ARGS);
extern Datum pg_get_function_result(PG_FUNCTION_ARGS); extern Datum pg_get_function_result(PG_FUNCTION_ARGS);
extern char *deparse_expression(Node *expr, List *dpcontext, extern char *deparse_expression(Node *expr, List *dpcontext,
bool forceprefix, bool showimplicit); bool forceprefix, bool showimplicit);

View File

@ -61,6 +61,14 @@ WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-';
-----+--------- -----+---------
(0 rows) (0 rows)
-- pronargdefaults should be 0 iff proargdefaults is null
SELECT p.oid, p.proname
FROM pg_proc AS p
WHERE pronargdefaults <> 0 OR proargdefaults IS NOT NULL;
oid | proname
-----+---------
(0 rows)
-- probin should be non-empty for C functions, null everywhere else -- probin should be non-empty for C functions, null everywhere else
SELECT p1.oid, p1.proname SELECT p1.oid, p1.proname
FROM pg_proc as p1 FROM pg_proc as p1

View File

@ -776,3 +776,190 @@ select pg_typeof(myleast(10, 1, 20, 33)); -- polymorphic input
integer integer
(1 row) (1 row)
-- test functions with parameter defaults
-- test basic functionality
create function dfunc(a int = 1, int = 2) returns int as $$
select $1 + $2;
$$ language sql;
select dfunc();
dfunc
-------
3
(1 row)
select dfunc(10);
dfunc
-------
12
(1 row)
select dfunc(10, 20);
dfunc
-------
30
(1 row)
drop function dfunc(); -- fail
ERROR: function dfunc() does not exist
drop function dfunc(int); -- fail
ERROR: function dfunc(integer) does not exist
drop function dfunc(int, int); -- ok
-- fail, gap in arguments with defaults
create function dfunc(a int = 1, b int) returns int as $$
select $1 + $2;
$$ language sql;
ERROR: parameter without default value specified after parameter with default value
-- check implicit coercion
create function dfunc(a int DEFAULT 1.0, int DEFAULT '-1') returns int as $$
select $1 + $2;
$$ language sql;
select dfunc();
dfunc
-------
0
(1 row)
create function dfunc(a text DEFAULT 'Hello', b text DEFAULT 'World') returns text as $$
select $1 || ', ' || $2;
$$ language sql;
select dfunc(); -- fail; which dfunc should be called? int or text
ERROR: functions with parameter defaults dfunc(text, text) and dfunc(integer, integer) are ambiguous
select dfunc('Hi'); -- ok
dfunc
-----------
Hi, World
(1 row)
select dfunc('Hi', 'City'); -- ok
dfunc
----------
Hi, City
(1 row)
select dfunc(0); -- ok
dfunc
-------
-1
(1 row)
select dfunc(10, 20); -- ok
dfunc
-------
30
(1 row)
drop function dfunc(int, int);
drop function dfunc(text, text);
create function dfunc(int = 1, int = 2) returns int as $$
select 2;
$$ language sql;
create function dfunc(int = 1, int = 2, int = 3, int = 4) returns int as $$
select 4;
$$ language sql;
-- Now, dfunc(nargs = 2) and dfunc(nargs = 4) are ambiguous when called
-- with 0 or 1 arguments. For 2 arguments, a normall call of
-- dfunc(nargs = 2) takes place.
select dfunc(); -- fail
ERROR: functions with parameter defaults dfunc(integer, integer, integer, integer) and dfunc(integer, integer) are ambiguous
select dfunc(1); -- fail
ERROR: functions with parameter defaults dfunc(integer, integer, integer, integer) and dfunc(integer, integer) are ambiguous
select dfunc(1, 2); -- ok
dfunc
-------
2
(1 row)
select dfunc(1, 2, 3); -- ok
dfunc
-------
4
(1 row)
select dfunc(1, 2, 3, 4); -- ok
dfunc
-------
4
(1 row)
drop function dfunc(int, int);
drop function dfunc(int, int, int, int);
-- default values are not allowed for output parameters
create function dfunc(out int = 20) returns int as $$
select 1;
$$ language sql;
ERROR: only IN and INOUT parameters can have default values
-- polymorphic parameter test
create function dfunc(anyelement = 'World'::text) returns text as $$
select 'Hello, ' || $1::text;
$$ language sql;
select dfunc();
dfunc
--------------
Hello, World
(1 row)
select dfunc(0);
dfunc
----------
Hello, 0
(1 row)
select dfunc(to_date('20081215','YYYYMMDD'));
dfunc
-------------------
Hello, 12-15-2008
(1 row)
select dfunc('City'::text);
dfunc
-------------
Hello, City
(1 row)
drop function dfunc(anyelement);
-- check null values
create function dfunc(int = null, int = null, int = null) returns int[] as $$
select array[$1, $2, $3];
$$ language sql;
select dfunc(1);
dfunc
---------------
{1,NULL,NULL}
(1 row)
select dfunc(1, 2);
dfunc
------------
{1,2,NULL}
(1 row)
select dfunc(1, 2, 3);
dfunc
---------
{1,2,3}
(1 row)
drop function dfunc(int, int, int);
-- The conflict detection algorithm doesn't consider the actual parameter
-- types. It detects any possible conflict for n arguments for some
-- function. This is unwanted behavior, but solving it needs a move of
-- coercion routines.
create function dfunc(int = 1, int = 2, int = 3) returns int as $$
select 3;
$$ language sql;
create function dfunc(int = 1, int = 2) returns int as $$
select 2;
$$ language sql;
-- for n = 1 dfunc(narg=2) and dfunc(narg=3) are ambiguous
select dfunc(1); -- fail
ERROR: functions with parameter defaults dfunc(integer, integer, integer) and dfunc(integer, integer) are ambiguous
create function dfunc(text) returns text as $$
select $1;
$$ language sql;
-- Will fail, it detects ambiguity between dfunc(int, int, int) and
-- dfunc(int, int), but dfunc(text) isn't in conflict with either.
select dfunc('Hi');
ERROR: functions with parameter defaults dfunc(integer, integer, integer) and dfunc(integer, integer) are ambiguous
drop function dfunc(int, int, int);
drop function dfunc(int, int);
drop function dfunc(text);

View File

@ -62,6 +62,11 @@ SELECT p1.oid, p1.proname
FROM pg_proc as p1 FROM pg_proc as p1
WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-'; WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-';
-- pronargdefaults should be 0 iff proargdefaults is null
SELECT p.oid, p.proname
FROM pg_proc AS p
WHERE pronargdefaults <> 0 OR proargdefaults IS NOT NULL;
-- probin should be non-empty for C functions, null everywhere else -- probin should be non-empty for C functions, null everywhere else
SELECT p1.oid, p1.proname SELECT p1.oid, p1.proname
FROM pg_proc as p1 FROM pg_proc as p1

View File

@ -480,3 +480,117 @@ select pg_typeof('' || ''); -- text
select pg_typeof(pg_typeof(0)); -- regtype select pg_typeof(pg_typeof(0)); -- regtype
select pg_typeof(array[1.2,55.5]); -- numeric[] select pg_typeof(array[1.2,55.5]); -- numeric[]
select pg_typeof(myleast(10, 1, 20, 33)); -- polymorphic input select pg_typeof(myleast(10, 1, 20, 33)); -- polymorphic input
-- test functions with parameter defaults
-- test basic functionality
create function dfunc(a int = 1, int = 2) returns int as $$
select $1 + $2;
$$ language sql;
select dfunc();
select dfunc(10);
select dfunc(10, 20);
drop function dfunc(); -- fail
drop function dfunc(int); -- fail
drop function dfunc(int, int); -- ok
-- fail, gap in arguments with defaults
create function dfunc(a int = 1, b int) returns int as $$
select $1 + $2;
$$ language sql;
-- check implicit coercion
create function dfunc(a int DEFAULT 1.0, int DEFAULT '-1') returns int as $$
select $1 + $2;
$$ language sql;
select dfunc();
create function dfunc(a text DEFAULT 'Hello', b text DEFAULT 'World') returns text as $$
select $1 || ', ' || $2;
$$ language sql;
select dfunc(); -- fail; which dfunc should be called? int or text
select dfunc('Hi'); -- ok
select dfunc('Hi', 'City'); -- ok
select dfunc(0); -- ok
select dfunc(10, 20); -- ok
drop function dfunc(int, int);
drop function dfunc(text, text);
create function dfunc(int = 1, int = 2) returns int as $$
select 2;
$$ language sql;
create function dfunc(int = 1, int = 2, int = 3, int = 4) returns int as $$
select 4;
$$ language sql;
-- Now, dfunc(nargs = 2) and dfunc(nargs = 4) are ambiguous when called
-- with 0 or 1 arguments. For 2 arguments, a normall call of
-- dfunc(nargs = 2) takes place.
select dfunc(); -- fail
select dfunc(1); -- fail
select dfunc(1, 2); -- ok
select dfunc(1, 2, 3); -- ok
select dfunc(1, 2, 3, 4); -- ok
drop function dfunc(int, int);
drop function dfunc(int, int, int, int);
-- default values are not allowed for output parameters
create function dfunc(out int = 20) returns int as $$
select 1;
$$ language sql;
-- polymorphic parameter test
create function dfunc(anyelement = 'World'::text) returns text as $$
select 'Hello, ' || $1::text;
$$ language sql;
select dfunc();
select dfunc(0);
select dfunc(to_date('20081215','YYYYMMDD'));
select dfunc('City'::text);
drop function dfunc(anyelement);
-- check null values
create function dfunc(int = null, int = null, int = null) returns int[] as $$
select array[$1, $2, $3];
$$ language sql;
select dfunc(1);
select dfunc(1, 2);
select dfunc(1, 2, 3);
drop function dfunc(int, int, int);
-- The conflict detection algorithm doesn't consider the actual parameter
-- types. It detects any possible conflict for n arguments for some
-- function. This is unwanted behavior, but solving it needs a move of
-- coercion routines.
create function dfunc(int = 1, int = 2, int = 3) returns int as $$
select 3;
$$ language sql;
create function dfunc(int = 1, int = 2) returns int as $$
select 2;
$$ language sql;
-- for n = 1 dfunc(narg=2) and dfunc(narg=3) are ambiguous
select dfunc(1); -- fail
create function dfunc(text) returns text as $$
select $1;
$$ language sql;
-- Will fail, it detects ambiguity between dfunc(int, int, int) and
-- dfunc(int, int), but dfunc(text) isn't in conflict with either.
select dfunc('Hi');
drop function dfunc(int, int, int);
drop function dfunc(int, int);
drop function dfunc(text);