diff options
-rw-r--r-- | src/backend/catalog/namespace.c | 112 | ||||
-rw-r--r-- | src/backend/parser/parse_oper.c | 188 | ||||
-rw-r--r-- | src/backend/utils/adt/regproc.c | 25 | ||||
-rw-r--r-- | src/include/catalog/namespace.h | 3 |
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); |