diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 1a1fa310cdbc188c7b7b7eae2e3fc7f90b10ad3c..f20838d12f12d0227c8d96a55c458d0c78e4f7ee 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.84 2006/04/25 14:11:53 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.85 2006/05/01 23:22:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -682,6 +682,95 @@ FunctionIsVisible(Oid funcid)
 }
 
 
+/*
+ * OpernameGetOprid
+ *		Given a possibly-qualified operator name and exact input datatypes,
+ *		look up the operator.  Returns InvalidOid if not found.
+ *
+ * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
+ * a postfix op.
+ *
+ * If the operator name is not schema-qualified, it is sought in the current
+ * namespace search path.
+ */
+Oid
+OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
+{
+	char	   *schemaname;
+	char	   *opername;
+	CatCList   *catlist;
+	ListCell   *l;
+
+	/* deconstruct the name list */
+	DeconstructQualifiedName(names, &schemaname, &opername);
+
+	if (schemaname)
+	{
+		/* search only in exact schema given */
+		Oid			namespaceId;
+		HeapTuple	opertup;
+
+		namespaceId = LookupExplicitNamespace(schemaname);
+		opertup = SearchSysCache(OPERNAMENSP,
+								 CStringGetDatum(opername),
+								 ObjectIdGetDatum(oprleft),
+								 ObjectIdGetDatum(oprright),
+								 ObjectIdGetDatum(namespaceId));
+		if (HeapTupleIsValid(opertup))
+		{
+			Oid		result = HeapTupleGetOid(opertup);
+
+			ReleaseSysCache(opertup);
+			return result;
+		}
+		return InvalidOid;
+	}
+
+	/* Search syscache by name and argument types */
+	catlist = SearchSysCacheList(OPERNAMENSP, 3,
+								 CStringGetDatum(opername),
+								 ObjectIdGetDatum(oprleft),
+								 ObjectIdGetDatum(oprright),
+								 0);
+
+	if (catlist->n_members == 0)
+	{
+		/* no hope, fall out early */
+		ReleaseSysCacheList(catlist);
+		return InvalidOid;
+	}
+
+	/*
+	 * We have to find the list member that is first in the search path,
+	 * if there's more than one.  This doubly-nested loop looks ugly,
+	 * but in practice there should usually be few catlist members.
+	 */
+	recomputeNamespacePath();
+
+	foreach(l, namespaceSearchPath)
+	{
+		Oid			namespaceId = lfirst_oid(l);
+		int			i;
+
+		for (i = 0; i < catlist->n_members; i++)
+		{
+			HeapTuple	opertup = &catlist->members[i]->tuple;
+			Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
+
+			if (operform->oprnamespace == namespaceId)
+			{
+				Oid		result = HeapTupleGetOid(opertup);
+
+				ReleaseSysCacheList(catlist);
+				return result;
+			}
+		}
+	}
+
+	ReleaseSysCacheList(catlist);
+	return InvalidOid;
+}
+
 /*
  * OpernameGetCandidates
  *		Given a possibly-qualified operator name and operator kind,
@@ -883,26 +972,13 @@ OperatorIsVisible(Oid oprid)
 		 * If it is in the path, it might still not be visible; it could be
 		 * hidden by another operator of the same name and arguments earlier
 		 * in the path.  So we must do a slow check to see if this is the same
-		 * operator that would be found by OpernameGetCandidates.
+		 * operator that would be found by OpernameGetOprId.
 		 */
 		char	   *oprname = NameStr(oprform->oprname);
-		FuncCandidateList clist;
-
-		visible = false;
 
-		clist = OpernameGetCandidates(list_make1(makeString(oprname)),
-									  oprform->oprkind);
-
-		for (; clist; clist = clist->next)
-		{
-			if (clist->args[0] == oprform->oprleft &&
-				clist->args[1] == oprform->oprright)
-			{
-				/* Found the expected entry; is it the right op? */
-				visible = (clist->oid == oprid);
-				break;
-			}
-		}
+		visible = (OpernameGetOprid(list_make1(makeString(oprname)),
+									oprform->oprleft, oprform->oprright)
+				   == oprid);
 	}
 
 	ReleaseSysCache(oprtup);
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index e483372e8520a92c2d438cb4efe9c41f6fd62ad3..b96849cfa285ed4b9501895c73cb2a6c34daa0b5 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.86 2006/03/14 22:48:21 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.87 2006/05/01 23:22:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,8 +29,7 @@
 #include "utils/typcache.h"
 
 
-static Oid binary_oper_exact(Oid arg1, Oid arg2,
-				  FuncCandidateList candidates);
+static Oid binary_oper_exact(List *opname, Oid arg1, Oid arg2);
 static FuncDetailCode oper_select_candidate(int nargs,
 					  Oid *input_typeids,
 					  FuncCandidateList candidates,
@@ -64,33 +63,31 @@ Oid
 LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
 			   bool noError, int location)
 {
-	FuncCandidateList clist;
-	char		oprkind;
-
-	if (!OidIsValid(oprleft))
-		oprkind = 'l';
-	else if (!OidIsValid(oprright))
-		oprkind = 'r';
-	else
-		oprkind = 'b';
-
-	clist = OpernameGetCandidates(opername, oprkind);
+	Oid			result;
 
-	while (clist)
-	{
-		if (clist->args[0] == oprleft && clist->args[1] == oprright)
-			return clist->oid;
-		clist = clist->next;
-	}
+	result = OpernameGetOprid(opername, oprleft, oprright);
+	if (OidIsValid(result))
+		return result;
 
 	/* we don't use op_error here because only an exact match is wanted */
 	if (!noError)
+	{
+		char		oprkind;
+
+		if (!OidIsValid(oprleft))
+			oprkind = 'l';
+		else if (!OidIsValid(oprright))
+			oprkind = 'r';
+		else
+			oprkind = 'b';
+
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
 				 errmsg("operator does not exist: %s",
 						op_signature_string(opername, oprkind,
 											oprleft, oprright)),
 				 parser_errposition(pstate, location)));
+	}
 
 	return InvalidOid;
 }
@@ -387,10 +384,9 @@ oprfuncid(Operator op)
  * be reduced to its base type to find an "exact" match.
  */
 static Oid
-binary_oper_exact(Oid arg1, Oid arg2,
-				  FuncCandidateList candidates)
+binary_oper_exact(List *opname, Oid arg1, Oid arg2)
 {
-	FuncCandidateList cand;
+	Oid			result;
 	bool		was_unknown = false;
 
 	/* Unspecified type for one of the arguments? then use the other */
@@ -405,11 +401,9 @@ binary_oper_exact(Oid arg1, Oid arg2,
 		was_unknown = true;
 	}
 
-	for (cand = candidates; cand != NULL; cand = cand->next)
-	{
-		if (arg1 == cand->args[0] && arg2 == cand->args[1])
-			return cand->oid;
-	}
+	result = OpernameGetOprid(opname, arg1, arg2);
+	if (OidIsValid(result))
+		return result;
 
 	if (was_unknown)
 	{
@@ -418,11 +412,9 @@ binary_oper_exact(Oid arg1, Oid arg2,
 
 		if (basetype != arg1)
 		{
-			for (cand = candidates; cand != NULL; cand = cand->next)
-			{
-				if (basetype == cand->args[0] && basetype == cand->args[1])
-					return cand->oid;
-			}
+			result = OpernameGetOprid(opname, basetype, basetype);
+			if (OidIsValid(result))
+				return result;
 		}
 	}
 
@@ -503,32 +495,33 @@ Operator
 oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
 	 bool noError, int location)
 {
-	FuncCandidateList clist;
-	Oid			inputOids[2];
 	Oid			operOid;
 	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
 	HeapTuple	tup = NULL;
 
-	/* Get binary operators of given name */
-	clist = OpernameGetCandidates(opname, 'b');
-
-	/* No operators found? Then fail... */
-	if (clist != NULL)
+	/*
+	 * First try for an "exact" match.
+	 */
+	operOid = binary_oper_exact(opname, ltypeId, rtypeId);
+	if (!OidIsValid(operOid))
 	{
 		/*
-		 * Check for an "exact" match.
+		 * Otherwise, search for the most suitable candidate.
 		 */
-		operOid = binary_oper_exact(ltypeId, rtypeId, clist);
-		if (!OidIsValid(operOid))
-		{
-			/*
-			 * Otherwise, search for the most suitable candidate.
-			 */
+		FuncCandidateList clist;
 
+		/* Get binary operators of given name */
+		clist = OpernameGetCandidates(opname, 'b');
+
+		/* No operators found? Then fail... */
+		if (clist != NULL)
+		{
 			/*
 			 * Unspecified type for one of the arguments? then use the other
 			 * (XXX this is probably dead code?)
 			 */
+			Oid			inputOids[2];
+
 			if (rtypeId == InvalidOid)
 				rtypeId = ltypeId;
 			else if (ltypeId == InvalidOid)
@@ -537,12 +530,13 @@ oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
 			inputOids[1] = rtypeId;
 			fdresult = oper_select_candidate(2, inputOids, clist, &operOid);
 		}
-		if (OidIsValid(operOid))
-			tup = SearchSysCache(OPEROID,
-								 ObjectIdGetDatum(operOid),
-								 0, 0, 0);
 	}
 
+	if (OidIsValid(operOid))
+		tup = SearchSysCache(OPEROID,
+							 ObjectIdGetDatum(operOid),
+							 0, 0, 0);
+
 	if (!HeapTupleIsValid(tup) && !noError)
 		op_error(pstate, opname, 'b', ltypeId, rtypeId, fdresult, location);
 
@@ -627,32 +621,26 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
 Operator
 right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 {
-	FuncCandidateList clist;
-	Oid			operOid = InvalidOid;
+	Oid			operOid;
 	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
 	HeapTuple	tup = NULL;
 
-	/* Find candidates */
-	clist = OpernameGetCandidates(op, 'r');
-
-	if (clist != NULL)
+	/*
+	 * First try for an "exact" match.
+	 */
+	operOid = OpernameGetOprid(op, arg, InvalidOid);
+	if (!OidIsValid(operOid))
 	{
 		/*
-		 * First, quickly check to see if there is an exactly matching
-		 * operator (there can be only one such entry in the list).
+		 * Otherwise, search for the most suitable candidate.
 		 */
-		FuncCandidateList clisti;
+		FuncCandidateList clist;
 
-		for (clisti = clist; clisti != NULL; clisti = clisti->next)
-		{
-			if (arg == clisti->args[0])
-			{
-				operOid = clisti->oid;
-				break;
-			}
-		}
+		/* Get postfix operators of given name */
+		clist = OpernameGetCandidates(op, 'r');
 
-		if (!OidIsValid(operOid))
+		/* No operators found? Then fail... */
+		if (clist != NULL)
 		{
 			/*
 			 * We must run oper_select_candidate even if only one candidate,
@@ -660,12 +648,13 @@ right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 			 */
 			fdresult = oper_select_candidate(1, &arg, clist, &operOid);
 		}
-		if (OidIsValid(operOid))
-			tup = SearchSysCache(OPEROID,
-								 ObjectIdGetDatum(operOid),
-								 0, 0, 0);
 	}
 
+	if (OidIsValid(operOid))
+		tup = SearchSysCache(OPEROID,
+							 ObjectIdGetDatum(operOid),
+							 0, 0, 0);
+
 	if (!HeapTupleIsValid(tup) && !noError)
 		op_error(pstate, op, 'r', arg, InvalidOid, fdresult, location);
 
@@ -690,50 +679,53 @@ right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 Operator
 left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 {
-	FuncCandidateList clist;
-	Oid			operOid = InvalidOid;
+	Oid			operOid;
 	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
 	HeapTuple	tup = NULL;
 
-	/* Find candidates */
-	clist = OpernameGetCandidates(op, 'l');
-
-	if (clist != NULL)
+	/*
+	 * First try for an "exact" match.
+	 */
+	operOid = OpernameGetOprid(op, InvalidOid, arg);
+	if (!OidIsValid(operOid))
 	{
 		/*
-		 * First, quickly check to see if there is an exactly matching
-		 * operator (there can be only one such entry in the list).
-		 *
-		 * The returned list has args in the form (0, oprright).  Move the
-		 * useful data into args[0] to keep oper_select_candidate simple. XXX
-		 * we are assuming here that we may scribble on the list!
+		 * Otherwise, search for the most suitable candidate.
 		 */
-		FuncCandidateList clisti;
+		FuncCandidateList clist;
+
+		/* Get prefix operators of given name */
+		clist = OpernameGetCandidates(op, 'l');
 
-		for (clisti = clist; clisti != NULL; clisti = clisti->next)
+		/* No operators found? Then fail... */
+		if (clist != NULL)
 		{
-			clisti->args[0] = clisti->args[1];
-			if (arg == clisti->args[0])
+			/*
+			 * The returned list has args in the form (0, oprright).
+			 * Move the useful data into args[0] to keep oper_select_candidate
+			 * simple.  XXX we are assuming here that we may scribble on the
+			 * list!
+			 */
+			FuncCandidateList clisti;
+
+			for (clisti = clist; clisti != NULL; clisti = clisti->next)
 			{
-				operOid = clisti->oid;
-				break;
+				clisti->args[0] = clisti->args[1];
 			}
-		}
 
-		if (!OidIsValid(operOid))
-		{
 			/*
 			 * We must run oper_select_candidate even if only one candidate,
 			 * otherwise we may falsely return a non-type-compatible operator.
 			 */
 			fdresult = oper_select_candidate(1, &arg, clist, &operOid);
 		}
-		if (OidIsValid(operOid))
-			tup = SearchSysCache(OPEROID,
-								 ObjectIdGetDatum(operOid),
-								 0, 0, 0);
 	}
 
+	if (OidIsValid(operOid))
+		tup = SearchSysCache(OPEROID,
+							 ObjectIdGetDatum(operOid),
+							 0, 0, 0);
+
 	if (!HeapTupleIsValid(tup) && !noError)
 		op_error(pstate, op, 'l', InvalidOid, arg, fdresult, location);
 
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index f5b0e2ab0c78bea24c3eda212cacf9254ee8b999..37bb0d929c343232848b61d63fbe05fa487dee4c 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/regproc.c,v 1.97 2006/03/05 15:58:43 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/regproc.c,v 1.98 2006/05/01 23:22:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -598,12 +598,10 @@ Datum
 regoperatorin(PG_FUNCTION_ARGS)
 {
 	char	   *opr_name_or_oid = PG_GETARG_CSTRING(0);
-	Oid			result = InvalidOid;
+	Oid			result;
 	List	   *names;
 	int			nargs;
 	Oid			argtypes[FUNC_MAX_ARGS];
-	char		oprkind;
-	FuncCandidateList clist;
 
 	/* '0' ? */
 	if (strcmp(opr_name_or_oid, "0") == 0)
@@ -642,28 +640,13 @@ regoperatorin(PG_FUNCTION_ARGS)
 				 errmsg("too many arguments"),
 				 errhint("Provide two argument types for operator.")));
 
-	if (argtypes[0] == InvalidOid)
-		oprkind = 'l';
-	else if (argtypes[1] == InvalidOid)
-		oprkind = 'r';
-	else
-		oprkind = 'b';
+	result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
 
-	clist = OpernameGetCandidates(names, oprkind);
-
-	for (; clist; clist = clist->next)
-	{
-		if (memcmp(clist->args, argtypes, 2 * sizeof(Oid)) == 0)
-			break;
-	}
-
-	if (clist == NULL)
+	if (!OidIsValid(result))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
 				 errmsg("operator does not exist: %s", opr_name_or_oid)));
 
-	result = clist->oid;
-
 	PG_RETURN_OID(result);
 }
 
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index e1389bc22422c533143734095f957125eaa3c082..ab354f53ac6074a89e1d2d7917e88a79944422e1 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.41 2006/04/25 14:11:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.42 2006/05/01 23:22:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,6 +44,7 @@ extern bool TypeIsVisible(Oid typid);
 extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs);
 extern bool FunctionIsVisible(Oid funcid);
 
+extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
 extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind);
 extern bool OperatorIsVisible(Oid oprid);