summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/catalog/namespace.c112
-rw-r--r--src/backend/parser/parse_oper.c188
-rw-r--r--src/backend/utils/adt/regproc.c25
-rw-r--r--src/include/catalog/namespace.h3
4 files changed, 190 insertions, 138 deletions
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 1a1fa310cd..f20838d12f 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 $
*
*-------------------------------------------------------------------------
*/
@@ -683,6 +683,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,
* retrieve a list of the possible matches.
@@ -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 e483372e85..b96849cfa2 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 f5b0e2ab0c..37bb0d929c 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 e1389bc224..ab354f53ac 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);