diff options
Diffstat (limited to 'src/backend/catalog/namespace.c')
-rw-r--r-- | src/backend/catalog/namespace.c | 87 |
1 files changed, 80 insertions, 7 deletions
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index f1763e5199c..6c83755a4c7 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 */ } |