diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/parse_func.c | 145 |
1 files changed, 80 insertions, 65 deletions
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index f72bddfc6c7..fc85ca89527 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.110 2001/08/09 18:28:18 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.111 2001/10/04 22:06:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -427,12 +427,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, } /* - * func_get_detail looks up the function in the catalogs, does - * disambiguation for polymorphic functions, handles inheritance, and - * returns the funcid and type and set or singleton status of the - * function's return value. it also returns the true argument types - * to the function. if func_get_detail returns true, the function - * exists. otherwise, there was an error. + * Is it a set, or a function? */ if (attisset) { /* we know all of these fields already */ @@ -454,61 +449,29 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, } else { - bool exists; + FuncDetailCode fdresult; - exists = func_get_detail(funcname, nargs, oid_array, &funcid, - &rettype, &retset, &true_oid_array); - if (!exists) + /* + * func_get_detail looks up the function in the catalogs, does + * disambiguation for polymorphic functions, handles inheritance, and + * returns the funcid and type and set or singleton status of the + * function's return value. it also returns the true argument types + * to the function. + */ + fdresult = func_get_detail(funcname, fargs, nargs, oid_array, + &funcid, &rettype, &retset, + &true_oid_array); + if (fdresult == FUNCDETAIL_COERCION) { - /* - * If we can't find a function (or can't find a unique - * function), see if this is really a type-coercion request: - * single-argument function call where the function name is a - * type name. If so, and if we can do the coercion trivially, - * just go ahead and do it without requiring there to be a - * real function for it. - * - * "Trivial" coercions are ones that involve binary-compatible - * types and ones that are coercing a previously-unknown-type - * literal constant to a specific type. - * - * DO NOT try to generalize this code to nontrivial coercions, - * because you'll just set up an infinite recursion between - * this routine and coerce_type! We have already failed to - * find a suitable "real" coercion function, so we have to - * fail unless this is a coercion that coerce_type can handle - * by itself. Make sure this code stays in sync with what - * coerce_type does! + * We can do it as a trivial coercion. + * coerce_type can handle these cases, so why duplicate code... */ - if (nargs == 1) - { - Oid targetType; - - targetType = GetSysCacheOid(TYPENAME, - PointerGetDatum(funcname), - 0, 0, 0); - if (OidIsValid(targetType)) - { - Oid sourceType = oid_array[0]; - Node *arg1 = lfirst(fargs); - - if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) || - sourceType == targetType || - IS_BINARY_COMPATIBLE(sourceType, targetType)) - { - - /* - * Ah-hah, we can do it as a trivial coercion. - * coerce_type can handle these cases, so why - * duplicate code... - */ - return coerce_type(pstate, arg1, - sourceType, targetType, -1); - } - } - } - + return coerce_type(pstate, lfirst(fargs), + oid_array[0], rettype, -1); + } + if (fdresult != FUNCDETAIL_NORMAL) + { /* * Oops. Time to die. * @@ -1130,6 +1093,7 @@ func_select_candidate(int nargs, /* func_get_detail() + * * Find the named function in the system catalogs. * * Attempt to find the named function in the system catalogs with @@ -1137,19 +1101,21 @@ func_select_candidate(int nargs, * (exact match) is as quick as possible. * * If an exact match isn't found: - * 1) get a vector of all possible input arg type arrays constructed + * 1) check for possible interpretation as a trivial type coercion + * 2) get a vector of all possible input arg type arrays constructed * from the superclasses of the original input arg types - * 2) get a list of all possible argument type arrays to the function + * 3) get a list of all possible argument type arrays to the function * with given name and number of arguments - * 3) for each input arg type array from vector #1: + * 4) for each input arg type array from vector #1: * a) find how many of the function arg type arrays from list #2 * it can be coerced to * b) if the answer is one, we have our function * c) if the answer is more than one, attempt to resolve the conflict * d) if the answer is zero, try the next array from vector #1 */ -bool +FuncDetailCode func_get_detail(char *funcname, + List *fargs, int nargs, Oid *argtypes, Oid *funcid, /* return value */ @@ -1158,6 +1124,7 @@ func_get_detail(char *funcname, Oid **true_typeids) /* return value */ { HeapTuple ftup; + CandidateList function_typeids; /* attempt to find with arguments exactly as specified... */ ftup = SearchSysCache(PROCNAME, @@ -1173,12 +1140,59 @@ func_get_detail(char *funcname, } else { + /* + * If we didn't find an exact match, next consider the possibility + * that this is really a type-coercion request: a single-argument + * function call where the function name is a type name. If so, + * and if we can do the coercion trivially (no run-time function + * call needed), then go ahead and treat the "function call" as + * a coercion. This interpretation needs to be given higher + * priority than interpretations involving a type coercion followed + * by a function call, otherwise we can produce surprising results. + * For example, we want "text(varchar)" to be interpreted as a + * trivial coercion, not as "text(name(varchar))" which the code + * below this point is entirely capable of selecting. + * + * "Trivial" coercions are ones that involve binary-compatible + * types and ones that are coercing a previously-unknown-type + * literal constant to a specific type. + * + * NB: it's important that this code stays in sync with what + * coerce_type can do, because the caller will try to apply + * coerce_type if we return FUNCDETAIL_COERCION. If we return + * that result for something coerce_type can't handle, we'll + * cause infinite recursion between this module and coerce_type! + */ + if (nargs == 1) + { + Oid targetType; + + targetType = GetSysCacheOid(TYPENAME, + PointerGetDatum(funcname), + 0, 0, 0); + if (OidIsValid(targetType)) + { + Oid sourceType = argtypes[0]; + Node *arg1 = lfirst(fargs); + + if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) || + sourceType == targetType || + IS_BINARY_COMPATIBLE(sourceType, targetType)) + { + /* Yup, it's a type coercion */ + *funcid = InvalidOid; + *rettype = targetType; + *retset = false; + *true_typeids = argtypes; + return FUNCDETAIL_COERCION; + } + } + } /* * didn't find an exact match, so now try to match up * candidates... */ - CandidateList function_typeids; function_typeids = func_get_candidates(funcname, nargs); @@ -1268,9 +1282,10 @@ func_get_detail(char *funcname, *rettype = pform->prorettype; *retset = pform->proretset; ReleaseSysCache(ftup); - return true; + return FUNCDETAIL_NORMAL; } - return false; + + return FUNCDETAIL_NOTFOUND; } /* func_get_detail() */ /* |