diff --git a/doc/src/sgml/typeconv.sgml b/doc/src/sgml/typeconv.sgml
index fdfc2934f9..70799e2804 100644
--- a/doc/src/sgml/typeconv.sgml
+++ b/doc/src/sgml/typeconv.sgml
@@ -458,6 +458,17 @@ this step.)
+If no exact match appears in the catalog, see whether the function call appears
+to be a trivial type coercion request. This happens if the function call
+has just one argument and the function name is the same as the (internal)
+name of some data type. Furthermore, the function argument must be either
+an unknown-type literal or a type that is binary-compatible with the named
+data type. When these conditions are met, the function argument is coerced
+to the named data type without any explicit function call.
+
+
+
+
Look for the best match.
@@ -519,17 +530,6 @@ then fail.
-
-
-If no best match could be identified, see whether the function call appears
-to be a trivial type coercion request. This happens if the function call
-has just one argument and the function name is the same as the (internal)
-name of some data type. Furthermore, the function argument must be either
-an unknown-type literal or a type that is binary-compatible with the named
-data type. When these conditions are met, the function argument is coerced
-to the named data type.
-
-
Examples
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 2304dd0b0c..aaf0630a2a 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.57 2001/08/21 16:36:02 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.58 2001/10/04 22:06:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -240,6 +240,7 @@ FuncIndexArgs(IndexInfo *indexInfo,
List *arglist;
int nargs = 0;
int i;
+ FuncDetailCode fdresult;
Oid funcid;
Oid rettype;
bool retset;
@@ -282,9 +283,18 @@ FuncIndexArgs(IndexInfo *indexInfo,
* that. So, check to make sure that the selected function has
* exact-match or binary-compatible input types.
*/
- if (!func_get_detail(funcIndex->name, nargs, argTypes,
- &funcid, &rettype, &retset, &true_typeids))
- func_error("DefineIndex", funcIndex->name, nargs, argTypes, NULL);
+ fdresult = func_get_detail(funcIndex->name, funcIndex->args,
+ nargs, argTypes,
+ &funcid, &rettype, &retset,
+ &true_typeids);
+ if (fdresult != FUNCDETAIL_NORMAL)
+ {
+ if (fdresult == FUNCDETAIL_COERCION)
+ elog(ERROR, "DefineIndex: functional index must use a real function, not a type coercion"
+ "\n\tTry specifying the index opclass you want to use, instead");
+ else
+ func_error("DefineIndex", funcIndex->name, nargs, argTypes, NULL);
+ }
if (retset)
elog(ERROR, "DefineIndex: cannot index on a function returning a set");
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index f72bddfc6c..fc85ca8952 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() */
/*
diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h
index 105781b96c..44c774db5e 100644
--- a/src/include/parser/parse_func.h
+++ b/src/include/parser/parse_func.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_func.h,v 1.31 2001/05/19 00:33:20 momjian Exp $
+ * $Id: parse_func.h,v 1.32 2001/10/04 22:06:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -38,6 +38,15 @@ typedef struct _CandidateList
struct _CandidateList *next;
} *CandidateList;
+/* Result codes for func_get_detail */
+typedef enum
+{
+ FUNCDETAIL_NOTFOUND, /* no suitable interpretation */
+ FUNCDETAIL_NORMAL, /* found a matching function */
+ FUNCDETAIL_COERCION /* it's a type coercion request */
+} FuncDetailCode;
+
+
extern Node *ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr,
int precedence);
extern Node *ParseFuncOrColumn(ParseState *pstate,
@@ -45,9 +54,10 @@ extern Node *ParseFuncOrColumn(ParseState *pstate,
bool agg_star, bool agg_distinct,
int precedence);
-extern bool func_get_detail(char *funcname, int nargs, Oid *argtypes,
- Oid *funcid, Oid *rettype,
- bool *retset, Oid **true_typeids);
+extern FuncDetailCode func_get_detail(char *funcname, List *fargs,
+ int nargs, Oid *argtypes,
+ Oid *funcid, Oid *rettype,
+ bool *retset, Oid **true_typeids);
extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId);