Commit a65a4942 authored by Tom Lane's avatar Tom Lane

Provide a namespace.c function for lookup of an operator with exact

input datatypes given, and use this before trying OpernameGetCandidates.
This is faster than the old method when there's an exact match, and it
does not seem materially slower when there's not.  And it definitely
makes some of the callers cleaner, because they didn't really want to
know about a list of candidates anyway.  Per discussion with Atsushi Ogawa.
parent 82a2881c
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -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 * OpernameGetCandidates
* Given a possibly-qualified operator name and operator kind, * Given a possibly-qualified operator name and operator kind,
...@@ -883,26 +972,13 @@ OperatorIsVisible(Oid oprid) ...@@ -883,26 +972,13 @@ OperatorIsVisible(Oid oprid)
* If it is in the path, it might still not be visible; it could be * 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 * 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 * 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); char *oprname = NameStr(oprform->oprname);
FuncCandidateList clist;
visible = false;
clist = OpernameGetCandidates(list_make1(makeString(oprname)), visible = (OpernameGetOprid(list_make1(makeString(oprname)),
oprform->oprkind); oprform->oprleft, oprform->oprright)
== oprid);
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;
}
}
} }
ReleaseSysCache(oprtup); ReleaseSysCache(oprtup);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -29,8 +29,7 @@
#include "utils/typcache.h" #include "utils/typcache.h"
static Oid binary_oper_exact(Oid arg1, Oid arg2, static Oid binary_oper_exact(List *opname, Oid arg1, Oid arg2);
FuncCandidateList candidates);
static FuncDetailCode oper_select_candidate(int nargs, static FuncDetailCode oper_select_candidate(int nargs,
Oid *input_typeids, Oid *input_typeids,
FuncCandidateList candidates, FuncCandidateList candidates,
...@@ -64,33 +63,31 @@ Oid ...@@ -64,33 +63,31 @@ Oid
LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
bool noError, int location) bool noError, int location)
{ {
FuncCandidateList clist; Oid result;
char oprkind;
if (!OidIsValid(oprleft))
oprkind = 'l';
else if (!OidIsValid(oprright))
oprkind = 'r';
else
oprkind = 'b';
clist = OpernameGetCandidates(opername, oprkind);
while (clist) result = OpernameGetOprid(opername, oprleft, oprright);
{ if (OidIsValid(result))
if (clist->args[0] == oprleft && clist->args[1] == oprright) return result;
return clist->oid;
clist = clist->next;
}
/* we don't use op_error here because only an exact match is wanted */ /* we don't use op_error here because only an exact match is wanted */
if (!noError) if (!noError)
{
char oprkind;
if (!OidIsValid(oprleft))
oprkind = 'l';
else if (!OidIsValid(oprright))
oprkind = 'r';
else
oprkind = 'b';
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION), (errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("operator does not exist: %s", errmsg("operator does not exist: %s",
op_signature_string(opername, oprkind, op_signature_string(opername, oprkind,
oprleft, oprright)), oprleft, oprright)),
parser_errposition(pstate, location))); parser_errposition(pstate, location)));
}
return InvalidOid; return InvalidOid;
} }
...@@ -387,10 +384,9 @@ oprfuncid(Operator op) ...@@ -387,10 +384,9 @@ oprfuncid(Operator op)
* be reduced to its base type to find an "exact" match. * be reduced to its base type to find an "exact" match.
*/ */
static Oid static Oid
binary_oper_exact(Oid arg1, Oid arg2, binary_oper_exact(List *opname, Oid arg1, Oid arg2)
FuncCandidateList candidates)
{ {
FuncCandidateList cand; Oid result;
bool was_unknown = false; bool was_unknown = false;
/* Unspecified type for one of the arguments? then use the other */ /* Unspecified type for one of the arguments? then use the other */
...@@ -405,11 +401,9 @@ binary_oper_exact(Oid arg1, Oid arg2, ...@@ -405,11 +401,9 @@ binary_oper_exact(Oid arg1, Oid arg2,
was_unknown = true; was_unknown = true;
} }
for (cand = candidates; cand != NULL; cand = cand->next) result = OpernameGetOprid(opname, arg1, arg2);
{ if (OidIsValid(result))
if (arg1 == cand->args[0] && arg2 == cand->args[1]) return result;
return cand->oid;
}
if (was_unknown) if (was_unknown)
{ {
...@@ -418,11 +412,9 @@ binary_oper_exact(Oid arg1, Oid arg2, ...@@ -418,11 +412,9 @@ binary_oper_exact(Oid arg1, Oid arg2,
if (basetype != arg1) if (basetype != arg1)
{ {
for (cand = candidates; cand != NULL; cand = cand->next) result = OpernameGetOprid(opname, basetype, basetype);
{ if (OidIsValid(result))
if (basetype == cand->args[0] && basetype == cand->args[1]) return result;
return cand->oid;
}
} }
} }
...@@ -503,32 +495,33 @@ Operator ...@@ -503,32 +495,33 @@ Operator
oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
bool noError, int location) bool noError, int location)
{ {
FuncCandidateList clist;
Oid inputOids[2];
Oid operOid; Oid operOid;
FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND; FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
HeapTuple tup = NULL; HeapTuple tup = NULL;
/* Get binary operators of given name */ /*
clist = OpernameGetCandidates(opname, 'b'); * First try for an "exact" match.
*/
/* No operators found? Then fail... */ operOid = binary_oper_exact(opname, ltypeId, rtypeId);
if (clist != NULL) if (!OidIsValid(operOid))
{ {
/* /*
* Check for an "exact" match. * Otherwise, search for the most suitable candidate.
*/ */
operOid = binary_oper_exact(ltypeId, rtypeId, clist); FuncCandidateList clist;
if (!OidIsValid(operOid))
{
/*
* Otherwise, search for the most suitable candidate.
*/
/* 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 * Unspecified type for one of the arguments? then use the other
* (XXX this is probably dead code?) * (XXX this is probably dead code?)
*/ */
Oid inputOids[2];
if (rtypeId == InvalidOid) if (rtypeId == InvalidOid)
rtypeId = ltypeId; rtypeId = ltypeId;
else if (ltypeId == InvalidOid) else if (ltypeId == InvalidOid)
...@@ -537,12 +530,13 @@ oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, ...@@ -537,12 +530,13 @@ oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
inputOids[1] = rtypeId; inputOids[1] = rtypeId;
fdresult = oper_select_candidate(2, inputOids, clist, &operOid); 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) if (!HeapTupleIsValid(tup) && !noError)
op_error(pstate, opname, 'b', ltypeId, rtypeId, fdresult, location); op_error(pstate, opname, 'b', ltypeId, rtypeId, fdresult, location);
...@@ -627,32 +621,26 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError) ...@@ -627,32 +621,26 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
Operator Operator
right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location) right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
{ {
FuncCandidateList clist; Oid operOid;
Oid operOid = InvalidOid;
FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND; FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
HeapTuple tup = NULL; HeapTuple tup = NULL;
/* Find candidates */ /*
clist = OpernameGetCandidates(op, 'r'); * First try for an "exact" match.
*/
if (clist != NULL) operOid = OpernameGetOprid(op, arg, InvalidOid);
if (!OidIsValid(operOid))
{ {
/* /*
* First, quickly check to see if there is an exactly matching * Otherwise, search for the most suitable candidate.
* operator (there can be only one such entry in the list).
*/ */
FuncCandidateList clisti; FuncCandidateList clist;
for (clisti = clist; clisti != NULL; clisti = clisti->next) /* Get postfix operators of given name */
{ clist = OpernameGetCandidates(op, 'r');
if (arg == clisti->args[0])
{
operOid = clisti->oid;
break;
}
}
if (!OidIsValid(operOid)) /* No operators found? Then fail... */
if (clist != NULL)
{ {
/* /*
* We must run oper_select_candidate even if only one candidate, * 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) ...@@ -660,12 +648,13 @@ right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
*/ */
fdresult = oper_select_candidate(1, &arg, clist, &operOid); 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) if (!HeapTupleIsValid(tup) && !noError)
op_error(pstate, op, 'r', arg, InvalidOid, fdresult, location); 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) ...@@ -690,50 +679,53 @@ right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
Operator Operator
left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location) left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
{ {
FuncCandidateList clist; Oid operOid;
Oid operOid = InvalidOid;
FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND; FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
HeapTuple tup = NULL; HeapTuple tup = NULL;
/* Find candidates */ /*
clist = OpernameGetCandidates(op, 'l'); * First try for an "exact" match.
*/
if (clist != NULL) operOid = OpernameGetOprid(op, InvalidOid, arg);
if (!OidIsValid(operOid))
{ {
/* /*
* First, quickly check to see if there is an exactly matching * Otherwise, search for the most suitable candidate.
* 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!
*/ */
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; clisti->args[0] = clisti->args[1];
break;
} }
}
if (!OidIsValid(operOid))
{
/* /*
* We must run oper_select_candidate even if only one candidate, * We must run oper_select_candidate even if only one candidate,
* otherwise we may falsely return a non-type-compatible operator. * otherwise we may falsely return a non-type-compatible operator.
*/ */
fdresult = oper_select_candidate(1, &arg, clist, &operOid); 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) if (!HeapTupleIsValid(tup) && !noError)
op_error(pstate, op, 'l', InvalidOid, arg, fdresult, location); op_error(pstate, op, 'l', InvalidOid, arg, fdresult, location);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * 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 ...@@ -598,12 +598,10 @@ Datum
regoperatorin(PG_FUNCTION_ARGS) regoperatorin(PG_FUNCTION_ARGS)
{ {
char *opr_name_or_oid = PG_GETARG_CSTRING(0); char *opr_name_or_oid = PG_GETARG_CSTRING(0);
Oid result = InvalidOid; Oid result;
List *names; List *names;
int nargs; int nargs;
Oid argtypes[FUNC_MAX_ARGS]; Oid argtypes[FUNC_MAX_ARGS];
char oprkind;
FuncCandidateList clist;
/* '0' ? */ /* '0' ? */
if (strcmp(opr_name_or_oid, "0") == 0) if (strcmp(opr_name_or_oid, "0") == 0)
...@@ -642,28 +640,13 @@ regoperatorin(PG_FUNCTION_ARGS) ...@@ -642,28 +640,13 @@ regoperatorin(PG_FUNCTION_ARGS)
errmsg("too many arguments"), errmsg("too many arguments"),
errhint("Provide two argument types for operator."))); errhint("Provide two argument types for operator.")));
if (argtypes[0] == InvalidOid) result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
oprkind = 'l';
else if (argtypes[1] == InvalidOid)
oprkind = 'r';
else
oprkind = 'b';
clist = OpernameGetCandidates(names, oprkind); if (!OidIsValid(result))
for (; clist; clist = clist->next)
{
if (memcmp(clist->args, argtypes, 2 * sizeof(Oid)) == 0)
break;
}
if (clist == NULL)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION), (errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("operator does not exist: %s", opr_name_or_oid))); errmsg("operator does not exist: %s", opr_name_or_oid)));
result = clist->oid;
PG_RETURN_OID(result); PG_RETURN_OID(result);
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -44,6 +44,7 @@ extern bool TypeIsVisible(Oid typid);
extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs); extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs);
extern bool FunctionIsVisible(Oid funcid); extern bool FunctionIsVisible(Oid funcid);
extern Oid OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind); extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind);
extern bool OperatorIsVisible(Oid oprid); extern bool OperatorIsVisible(Oid oprid);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment