* 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 $
*
*-------------------------------------------------------------------------
*/
}
+/*
+ * 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,
* 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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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,
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;
}
* 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 */
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)
{
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;
}
}
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)
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);
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,
*/
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);
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);