diff --git a/doc/src/sgml/typeconv.sgml b/doc/src/sgml/typeconv.sgml
index fdfc2934f9d0f46aa0b96c56bfa729e1fe29317b..70799e280448c2cc4e3e85fb0bd61cc8eafd50cf 100644
--- a/doc/src/sgml/typeconv.sgml
+++ b/doc/src/sgml/typeconv.sgml
@@ -458,6 +458,17 @@ this step.)
 </para></step>
 <step performance="required">
 <para>
+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.
+</para>
+</step>
+<step performance="required">
+<para>
 Look for the best match.
 </para>
 <substeps>
@@ -519,17 +530,6 @@ then fail.
 </step>
 </substeps>
 </step>
-<step performance="required">
-<para>
-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.
-</para>
-</step>
 </procedure>
 
 <bridgehead renderas="sect2">Examples</bridgehead>
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 2304dd0b0cdc355e5916b5dec56218da47cc201f..aaf0630a2a7af7184d12b20e2d6fa0a9b2541136 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 f72bddfc6c77802bd13f0fba5777aa002222b8f3..fc85ca89527c5765c4da0e2f95c4596113e63a77 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 105781b96c3984e324b92e1dcbf006a934172542..44c774db5ed9d1cb39c404eed9e6cdcedff9c1ac 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);