summaryrefslogtreecommitdiff
path: root/src/backend/catalog
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2008-12-04 17:51:28 +0000
committerPeter Eisentraut <peter_e@gmx.net>2008-12-04 17:51:28 +0000
commit455dffbb73f9875c39f2ab544420454168a8c68c (patch)
treee440fabcfe1bf24cf0e44723aa329150af141ea2 /src/backend/catalog
parent7b640b0345dc4fbd39ff568700985b432f6afa07 (diff)
downloadpostgresql-455dffbb73f9875c39f2ab544420454168a8c68c.tar.gz
Default values for function arguments
Pavel Stehule, with some tweaks by Peter Eisentraut
Diffstat (limited to 'src/backend/catalog')
-rw-r--r--src/backend/catalog/namespace.c87
-rw-r--r--src/backend/catalog/pg_aggregate.c7
-rw-r--r--src/backend/catalog/pg_proc.c13
3 files changed, 95 insertions, 12 deletions
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index f1763e5199..6c83755a4c 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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,
* 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
* all namespaces in the search path. The return list will never contain
* multiple entries with identical argument lists --- in the multiple-
@@ -621,13 +626,45 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
int pathpos = 0;
bool variadic;
Oid va_elem_type;
+ List *defaults = NIL;
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.
* If expand_variadic is false, we should just ignore variadic-ness.
*/
- if (expand_variadic)
+ if (pronargs <= nargs && expand_variadic)
{
va_elem_type = procform->provariadic;
variadic = OidIsValid(va_elem_type);
@@ -638,11 +675,16 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
variadic = false;
}
+ Assert(!variadic || !defaults);
+
/* Ignore if it doesn't match requested argument count */
if (nargs >= 0 &&
- (variadic ? (pronargs > nargs) : (pronargs != nargs)))
+ (variadic ? (pronargs > nargs) : (defaults ? (pronargs < nargs) : (pronargs != nargs))))
continue;
+ Assert(!variadic || (pronargs <= nargs));
+ Assert(!defaults || (pronargs > nargs));
+
if (OidIsValid(namespaceId))
{
/* Consider only procs in specified namespace */
@@ -681,6 +723,7 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
newResult->pathpos = pathpos;
newResult->oid = HeapTupleGetOid(proctup);
newResult->nargs = effective_nargs;
+ newResult->argdefaults = defaults;
memcpy(newResult->args, procform->proargtypes.values,
pronargs * sizeof(Oid));
if (variadic)
@@ -695,6 +738,8 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
else
newResult->nvargs = 0;
+ any_variadic = variadic || defaults;
+
/*
* 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
@@ -704,6 +749,9 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
*/
if (any_variadic || !OidIsValid(namespaceId))
{
+ if (defaults)
+ effective_nargs = nargs;
+
/*
* If we have an ordered list from SearchSysCacheList (the normal
* case), then any conflicting proc must immediately adjoin this
@@ -733,11 +781,21 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
prevResult;
prevResult = prevResult->next)
{
- if (effective_nargs == prevResult->nargs &&
- memcmp(newResult->args,
- prevResult->args,
- effective_nargs * sizeof(Oid)) == 0)
+ if (!defaults)
+ {
+ if (effective_nargs == prevResult->nargs &&
+ memcmp(newResult->args,
+ prevResult->args,
+ effective_nargs * sizeof(Oid)) == 0)
+ break;
+ }
+ else
+ {
+ if (memcmp(newResult->args,
+ prevResult->args,
+ effective_nargs * sizeof(Oid)) == 0)
break;
+ }
}
}
if (prevResult)
@@ -777,6 +835,20 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
pfree(newResult);
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 */
Assert(prevResult->nvargs > 0);
}
@@ -784,6 +856,7 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
prevResult->pathpos = pathpos;
prevResult->oid = newResult->oid;
prevResult->nvargs = newResult->nvargs;
+ prevResult->argdefaults = newResult->argdefaults;
pfree(newResult);
continue; /* args are same, of course */
}
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index fc5ed83937..7cd0d513ed 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -8,7 +8,7 @@
*
*
* 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), /* proconfig */
1, /* procost */
- 0); /* prorows */
+ 0, /* prorows */
+ NULL); /* parameterDefaults */
/*
* 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,
&fnOid, rettype, &retset, &nvargs,
- &true_oid_array);
+ &true_oid_array, NULL);
/* only valid case is a normal function not returning a set */
if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index e17aa43fd5..1b414e3e5a 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
*
*
* 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 proconfig,
float4 procost,
- float4 prorows)
+ float4 prorows,
+ List *parameterDefaults)
{
Oid retval;
int parameterCount;
@@ -295,6 +296,7 @@ ProcedureCreate(const char *procedureName,
values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet);
values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility);
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_proargtypes - 1] = PointerGetDatum(parameterTypes);
if (allParameterTypes != PointerGetDatum(NULL))
@@ -309,6 +311,13 @@ ProcedureCreate(const char *procedureName,
values[Anum_pg_proc_proargnames - 1] = parameterNames;
else
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);
if (probin)
values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin);