diff options
Diffstat (limited to 'src/backend')
25 files changed, 1122 insertions, 1053 deletions
diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index f0c7ef5a0d..7bfede27b5 100644 --- a/src/backend/catalog/indexing.c +++ b/src/backend/catalog/indexing.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.88 2002/04/11 19:59:57 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.89 2002/04/16 23:08:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -62,7 +62,7 @@ char *Name_pg_namespace_indices[Num_pg_namespace_indices] = char *Name_pg_opclass_indices[Num_pg_opclass_indices] = {OpclassAmNameIndex, OpclassOidIndex}; char *Name_pg_operator_indices[Num_pg_operator_indices] = -{OperatorOidIndex, OperatorNameIndex}; +{OperatorOidIndex, OperatorNameNspIndex}; char *Name_pg_proc_indices[Num_pg_proc_indices] = {ProcedureOidIndex, ProcedureNameNspIndex}; char *Name_pg_relcheck_indices[Num_pg_relcheck_indices] = diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index 77b6ceb78d..15fdb01ed3 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 - * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.9 2002/04/15 22:33:21 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.10 2002/04/16 23:08:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,6 +27,7 @@ #include "catalog/namespace.h" #include "catalog/pg_inherits.h" #include "catalog/pg_namespace.h" +#include "catalog/pg_operator.h" #include "catalog/pg_proc.h" #include "catalog/pg_shadow.h" #include "lib/stringinfo.h" @@ -479,6 +480,179 @@ FuncnameGetCandidates(List *names, int nargs) } /* + * OpernameGetCandidates + * Given a possibly-qualified operator name and operator kind, + * retrieve a list of the possible matches. + * + * We search a single namespace if the operator name is qualified, else + * all namespaces in the search path. The return list will never contain + * multiple entries with identical argument types --- in the multiple- + * namespace case, we arrange for entries in earlier namespaces to mask + * identical entries in later namespaces. + * + * The returned items always have two args[] entries --- one or the other + * will be InvalidOid for a prefix or postfix oprkind. + */ +FuncCandidateList +OpernameGetCandidates(List *names, char oprkind) +{ + FuncCandidateList resultList = NULL; + char *catalogname; + char *schemaname = NULL; + char *opername = NULL; + Oid namespaceId; + CatCList *catlist; + int i; + + /* deconstruct the name list */ + switch (length(names)) + { + case 1: + opername = strVal(lfirst(names)); + break; + case 2: + schemaname = strVal(lfirst(names)); + opername = strVal(lsecond(names)); + break; + case 3: + catalogname = strVal(lfirst(names)); + schemaname = strVal(lsecond(names)); + opername = strVal(lfirst(lnext(lnext(names)))); + /* + * We check the catalog name and then ignore it. + */ + if (strcmp(catalogname, DatabaseName) != 0) + elog(ERROR, "Cross-database references are not implemented"); + break; + default: + elog(ERROR, "Improper qualified name (too many dotted names)"); + break; + } + + if (schemaname) + { + /* use exact schema given */ + namespaceId = GetSysCacheOid(NAMESPACENAME, + CStringGetDatum(schemaname), + 0, 0, 0); + if (!OidIsValid(namespaceId)) + elog(ERROR, "Namespace \"%s\" does not exist", + schemaname); + } + else + { + /* flag to indicate we need namespace search */ + namespaceId = InvalidOid; + } + + /* Search syscache by name only */ + catlist = SearchSysCacheList(OPERNAMENSP, 1, + CStringGetDatum(opername), + 0, 0, 0); + + for (i = 0; i < catlist->n_members; i++) + { + HeapTuple opertup = &catlist->members[i]->tuple; + Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup); + int pathpos = 0; + FuncCandidateList newResult; + + /* Ignore operators of wrong kind */ + if (operform->oprkind != oprkind) + continue; + + if (OidIsValid(namespaceId)) + { + /* Consider only opers in specified namespace */ + if (operform->oprnamespace != namespaceId) + continue; + /* No need to check args, they must all be different */ + } + else + { + /* Consider only opers that are in the search path */ + if (pathContainsSystemNamespace || + !IsSystemNamespace(operform->oprnamespace)) + { + List *nsp; + + foreach(nsp, namespaceSearchPath) + { + pathpos++; + if (operform->oprnamespace == (Oid) lfirsti(nsp)) + break; + } + if (nsp == NIL) + continue; /* oper is not in search path */ + } + + /* + * Okay, it's in the search path, but does it have the same + * arguments as something we already accepted? If so, keep + * only the one that appears earlier in the search path. + * + * If we have an ordered list from SearchSysCacheList (the + * normal case), then any conflicting oper must immediately + * adjoin this one in the list, so we only need to look at + * the newest result item. If we have an unordered list, + * we have to scan the whole result list. + */ + if (resultList) + { + FuncCandidateList prevResult; + + if (catlist->ordered) + { + if (operform->oprleft == resultList->args[0] && + operform->oprright == resultList->args[1]) + prevResult = resultList; + else + prevResult = NULL; + } + else + { + for (prevResult = resultList; + prevResult; + prevResult = prevResult->next) + { + if (operform->oprleft == prevResult->args[0] && + operform->oprright == prevResult->args[1]) + break; + } + } + if (prevResult) + { + /* We have a match with a previous result */ + Assert(pathpos != prevResult->pathpos); + if (pathpos > prevResult->pathpos) + continue; /* keep previous result */ + /* replace previous result */ + prevResult->pathpos = pathpos; + prevResult->oid = opertup->t_data->t_oid; + continue; /* args are same, of course */ + } + } + } + + /* + * Okay to add it to result list + */ + newResult = (FuncCandidateList) + palloc(sizeof(struct _FuncCandidateList) + sizeof(Oid)); + newResult->pathpos = pathpos; + newResult->oid = opertup->t_data->t_oid; + newResult->args[0] = operform->oprleft; + newResult->args[1] = operform->oprright; + newResult->next = resultList; + resultList = newResult; + } + + ReleaseSysCacheList(catlist); + + return resultList; +} + +/* * QualifiedNameGetCreationNamespace * Given a possibly-qualified name for an object (in List-of-Values * format), determine what namespace the object should be created in. diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c index 41023b7edc..3a4bb1bba3 100644 --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.65 2002/04/09 20:35:47 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.66 2002/04/16 23:08:10 tgl Exp $ * * NOTES * these routines moved here from commands/define.c and somewhat cleaned up. @@ -20,42 +20,41 @@ #include "access/heapam.h" #include "catalog/catname.h" #include "catalog/indexing.h" +#include "catalog/namespace.h" #include "catalog/pg_operator.h" -#include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "miscadmin.h" #include "parser/parse_func.h" +#include "parser/parse_oper.h" #include "utils/builtins.h" -#include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/syscache.h" static Oid OperatorGet(const char *operatorName, + Oid operatorNamespace, Oid leftObjectId, Oid rightObjectId, bool *defined); +static Oid OperatorLookup(List *operatorName, + Oid leftObjectId, + Oid rightObjectId, + bool *defined); + static Oid OperatorShellMake(const char *operatorName, + Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId); -static void OperatorDef(const char *operatorName, - Oid leftTypeId, - Oid rightTypeId, - List *procedureName, - uint16 precedence, - bool isLeftAssociative, - const char *commutatorName, - const char *negatorName, - List *restrictionName, - List *joinName, - bool canHash, - const char *leftSortName, - const char *rightSortName); - static void OperatorUpd(Oid baseId, Oid commId, Oid negId); +static Oid get_other_operator(List *otherOp, + Oid otherLeftTypeId, Oid otherRightTypeId, + const char *operatorName, Oid operatorNamespace, + Oid leftTypeId, Oid rightTypeId, + bool isCommutator); + /* * Check whether a proposed operator name is legal @@ -114,76 +113,36 @@ validOperatorName(const char *name) } -/* ---------------------------------------------------------------- - * OperatorGet +/* + * OperatorGet * - * finds the operator associated with the specified name - * and left and right type IDs. + * finds an operator given an exact specification (name, namespace, + * left and right type IDs). * - * operatorName -- name of operator to fetch - * leftObjectId -- left data type oid of operator to fetch - * rightObjectId -- right data type oid of operator to fetch - * defined -- set TRUE if defined (not a shell) - * ---------------------------------------------------------------- + * *defined is set TRUE if defined (not a shell) */ static Oid OperatorGet(const char *operatorName, + Oid operatorNamespace, Oid leftObjectId, Oid rightObjectId, bool *defined) { - Relation pg_operator_desc; - HeapScanDesc pg_operator_scan; HeapTuple tup; - ScanKeyData opKey[3]; Oid operatorObjectId; - if (!(OidIsValid(leftObjectId) || OidIsValid(rightObjectId))) - elog(ERROR, "operator %s must have at least one operand type", - operatorName); - - /* - * open the pg_operator relation - */ - pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock); - - /* - * form scan key - */ - ScanKeyEntryInitialize(&opKey[0], 0x0, - Anum_pg_operator_oprname, - F_NAMEEQ, - PointerGetDatum(operatorName)); - ScanKeyEntryInitialize(&opKey[1], 0x0, - Anum_pg_operator_oprleft, - F_OIDEQ, - ObjectIdGetDatum(leftObjectId)); - ScanKeyEntryInitialize(&opKey[2], 0x0, - Anum_pg_operator_oprright, - F_OIDEQ, - ObjectIdGetDatum(rightObjectId)); - - /* - * begin the scan - */ - pg_operator_scan = heap_beginscan(pg_operator_desc, - 0, - SnapshotSelf, /* no cache? */ - 3, - opKey); - - /* - * fetch the operator tuple, if it exists, and determine the proper - * return oid value. - */ - tup = heap_getnext(pg_operator_scan, 0); - + tup = SearchSysCache(OPERNAMENSP, + PointerGetDatum(operatorName), + ObjectIdGetDatum(leftObjectId), + ObjectIdGetDatum(rightObjectId), + ObjectIdGetDatum(operatorNamespace)); if (HeapTupleIsValid(tup)) { regproc oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode; operatorObjectId = tup->t_data->t_oid; *defined = RegProcedureIsValid(oprcode); + ReleaseSysCache(tup); } else { @@ -191,21 +150,48 @@ OperatorGet(const char *operatorName, *defined = false; } - /* - * close the scan and return the oid. - */ - heap_endscan(pg_operator_scan); - heap_close(pg_operator_desc, AccessShareLock); + return operatorObjectId; +} + +/* + * OperatorLookup + * + * looks up an operator given a possibly-qualified name and + * left and right type IDs. + * + * *defined is set TRUE if defined (not a shell) + */ +static Oid +OperatorLookup(List *operatorName, + Oid leftObjectId, + Oid rightObjectId, + bool *defined) +{ + Oid operatorObjectId; + regproc oprcode; + + operatorObjectId = LookupOperName(operatorName, leftObjectId, + rightObjectId); + if (!OidIsValid(operatorObjectId)) + { + *defined = false; + return InvalidOid; + } + + oprcode = get_opcode(operatorObjectId); + *defined = RegProcedureIsValid(oprcode); return operatorObjectId; } + /* * OperatorShellMake * Make a "shell" entry for a not-yet-existing operator. */ static Oid OperatorShellMake(const char *operatorName, + Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId) { @@ -225,11 +211,6 @@ OperatorShellMake(const char *operatorName, elog(ERROR, "\"%s\" is not a valid operator name", operatorName); /* - * open pg_operator - */ - pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock); - - /* * initialize our *nulls and *values arrays */ for (i = 0; i < Natts_pg_operator; ++i) @@ -244,28 +225,35 @@ OperatorShellMake(const char *operatorName, */ i = 0; namestrcpy(&oname, operatorName); - values[i++] = NameGetDatum(&oname); - values[i++] = Int32GetDatum(GetUserId()); - values[i++] = UInt16GetDatum(0); - values[i++] = CharGetDatum('b'); /* assume it's binary */ - values[i++] = BoolGetDatum(false); - values[i++] = BoolGetDatum(false); - values[i++] = ObjectIdGetDatum(leftTypeId); - values[i++] = ObjectIdGetDatum(rightTypeId); - values[i++] = ObjectIdGetDatum(InvalidOid); - values[i++] = ObjectIdGetDatum(InvalidOid); - values[i++] = ObjectIdGetDatum(InvalidOid); - values[i++] = ObjectIdGetDatum(InvalidOid); - values[i++] = ObjectIdGetDatum(InvalidOid); - values[i++] = ObjectIdGetDatum(InvalidOid); - values[i++] = ObjectIdGetDatum(InvalidOid); - values[i++] = ObjectIdGetDatum(InvalidOid); + values[i++] = NameGetDatum(&oname); /* oprname */ + values[i++] = ObjectIdGetDatum(operatorNamespace); /* oprnamespace */ + values[i++] = Int32GetDatum(GetUserId()); /* oprowner */ + values[i++] = UInt16GetDatum(0); /* oprprec */ + values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); /* oprkind */ + values[i++] = BoolGetDatum(false); /* oprisleft */ + values[i++] = BoolGetDatum(false); /* oprcanhash */ + values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */ + values[i++] = ObjectIdGetDatum(rightTypeId); /* oprright */ + values[i++] = ObjectIdGetDatum(InvalidOid); /* oprresult */ + values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcom */ + values[i++] = ObjectIdGetDatum(InvalidOid); /* oprnegate */ + values[i++] = ObjectIdGetDatum(InvalidOid); /* oprlsortop */ + values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrsortop */ + values[i++] = ObjectIdGetDatum(InvalidOid); /* oprltcmpop */ + values[i++] = ObjectIdGetDatum(InvalidOid); /* oprgtcmpop */ + values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcode */ + values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrest */ + values[i++] = ObjectIdGetDatum(InvalidOid); /* oprjoin */ /* - * create a new operator tuple + * open pg_operator */ + pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock); tupDesc = pg_operator_desc->rd_att; + /* + * create a new operator tuple + */ tup = heap_formtuple(tupDesc, values, nulls); /* @@ -293,8 +281,26 @@ OperatorShellMake(const char *operatorName, return operatorObjectId; } -/* -------------------------------- - * OperatorDef +/* + * OperatorCreate + * + * "X" indicates an optional argument (i.e. one that can be NULL or 0) + * operatorName name for new operator + * operatorNamespace namespace for new operator + * leftTypeId X left type ID + * rightTypeId X right type ID + * procedureName procedure for operator + * precedence operator precedence + * isLeftAssociative operator is left associative + * commutatorName X commutator operator + * negatorName X negator operator + * restrictionName X restriction sel. procedure + * joinName X join sel. procedure + * canHash hash join can be used with this operator + * leftSortName X left sort operator (for merge join) + * rightSortName X right sort operator (for merge join) + * ltCompareName X L<R compare operator (for merge join) + * gtCompareName X L>R compare operator (for merge join) * * This routine gets complicated because it allows the user to * specify operators that do not exist. For example, if operator @@ -354,68 +360,73 @@ OperatorShellMake(const char *operatorName, * else if a new operator is being created * create a tuple using heap_formtuple * call heap_insert - * -------------------------------- - * "X" indicates an optional argument (i.e. one that can be NULL) - * operatorName; -- operator name - * leftTypeId; -- X left type id - * rightTypeId; -- X right type id - * procedureName; -- procedure name for operator code - * precedence; -- operator precedence - * isLeftAssociative; -- operator is left associative? - * commutatorName; -- X commutator operator name - * negatorName; -- X negator operator name - * restrictionName; -- X restriction sel. procedure name - * joinName; -- X join sel. procedure name - * canHash; -- can hash join be used with operator? - * leftSortName; -- X left sort operator (for merge join) - * rightSortName; -- X right sort operator (for merge join) */ -static void -OperatorDef(const char *operatorName, - Oid leftTypeId, - Oid rightTypeId, - List *procedureName, - uint16 precedence, - bool isLeftAssociative, - const char *commutatorName, - const char *negatorName, - List *restrictionName, - List *joinName, - bool canHash, - const char *leftSortName, - const char *rightSortName) +void +OperatorCreate(const char *operatorName, + Oid operatorNamespace, + Oid leftTypeId, + Oid rightTypeId, + List *procedureName, + uint16 precedence, + bool isLeftAssociative, + List *commutatorName, + List *negatorName, + List *restrictionName, + List *joinName, + bool canHash, + List *leftSortName, + List *rightSortName, + List *ltCompareName, + List *gtCompareName) { Relation pg_operator_desc; - HeapScanDesc pg_operator_scan; HeapTuple tup; char nulls[Natts_pg_operator]; char replaces[Natts_pg_operator]; Datum values[Natts_pg_operator]; Oid operatorObjectId; bool operatorAlreadyDefined; - Oid commutatorId = InvalidOid; - Oid negatorId = InvalidOid; + Oid procOid; + Oid operResultType; + Oid commutatorId, + negatorId, + leftSortId, + rightSortId, + ltCompareId, + gtCompareId, + restOid, + joinOid; bool selfCommutator = false; - const char *name[4]; Oid typeId[FUNC_MAX_ARGS]; int nargs; - Oid procOid; NameData oname; TupleDesc tupDesc; - ScanKeyData opKey[3]; - int i, - j; + int i; /* - * validate operator name + * Sanity checks */ if (!validOperatorName(operatorName)) elog(ERROR, "\"%s\" is not a valid operator name", operatorName); - if (!(OidIsValid(leftTypeId) || OidIsValid(rightTypeId))) - elog(ERROR, "operator must have at least one operand type"); + if (!OidIsValid(leftTypeId) && !OidIsValid(rightTypeId)) + elog(ERROR, "at least one of leftarg or rightarg must be specified"); + + if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId))) + { + /* If it's not a binary op, these things mustn't be set: */ + if (commutatorName) + elog(ERROR, "only binary operators can have commutators"); + if (joinName) + elog(ERROR, "only binary operators can have join selectivity"); + if (canHash) + elog(ERROR, "only binary operators can hash"); + if (leftSortName || rightSortName || ltCompareName || gtCompareName) + elog(ERROR, "only binary operators can mergejoin"); + } operatorObjectId = OperatorGet(operatorName, + operatorNamespace, leftTypeId, rightTypeId, &operatorAlreadyDefined); @@ -429,13 +440,6 @@ OperatorDef(const char *operatorName, * filling in a previously-created shell. */ - for (i = 0; i < Natts_pg_operator; ++i) - { - values[i] = (Datum) NULL; - replaces[i] = 'r'; - nulls[i] = ' '; - } - /* * Look up registered procedures -- find the return type of * procedureName to place in "result" field. Do this before shells are @@ -461,17 +465,13 @@ OperatorDef(const char *operatorName, procOid = LookupFuncName(procedureName, nargs, typeId); if (!OidIsValid(procOid)) func_error("OperatorDef", procedureName, nargs, typeId, NULL); - - values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procOid); - values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(get_func_rettype(procOid)); + operResultType = get_func_rettype(procOid); /* * find restriction estimator */ if (restrictionName) - { /* optional */ - Oid restOid; - + { MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid)); typeId[0] = 0; /* Query (opaque type) */ typeId[1] = OIDOID; /* operator OID */ @@ -481,19 +481,15 @@ OperatorDef(const char *operatorName, restOid = LookupFuncName(restrictionName, 4, typeId); if (!OidIsValid(restOid)) func_error("OperatorDef", restrictionName, 4, typeId, NULL); - - values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restOid); } else - values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid); + restOid = InvalidOid; /* * find join estimator */ if (joinName) - { /* optional */ - Oid joinOid; - + { MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid)); typeId[0] = 0; /* Query (opaque type) */ typeId[1] = OIDOID; /* operator OID */ @@ -502,170 +498,148 @@ OperatorDef(const char *operatorName, joinOid = LookupFuncName(joinName, 3, typeId); if (!OidIsValid(joinOid)) func_error("OperatorDef", joinName, 3, typeId, NULL); - - values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid); } else - values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid); + joinOid = InvalidOid; /* * set up values in the operator tuple */ + + for (i = 0; i < Natts_pg_operator; ++i) + { + values[i] = (Datum) NULL; + replaces[i] = 'r'; + nulls[i] = ' '; + } + i = 0; namestrcpy(&oname, operatorName); - values[i++] = NameGetDatum(&oname); - values[i++] = Int32GetDatum(GetUserId()); - values[i++] = UInt16GetDatum(precedence); - values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); - values[i++] = BoolGetDatum(isLeftAssociative); - values[i++] = BoolGetDatum(canHash); - values[i++] = ObjectIdGetDatum(leftTypeId); - values[i++] = ObjectIdGetDatum(rightTypeId); - - ++i; /* Skip "oprresult", it was filled in - * above */ + values[i++] = NameGetDatum(&oname); /* oprname */ + values[i++] = ObjectIdGetDatum(operatorNamespace); /* oprnamespace */ + values[i++] = Int32GetDatum(GetUserId()); /* oprowner */ + values[i++] = UInt16GetDatum(precedence); /* oprprec */ + values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); /* oprkind */ + values[i++] = BoolGetDatum(isLeftAssociative); /* oprisleft */ + values[i++] = BoolGetDatum(canHash); /* oprcanhash */ + values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */ + values[i++] = ObjectIdGetDatum(rightTypeId); /* oprright */ + values[i++] = ObjectIdGetDatum(operResultType); /* oprresult */ /* * Set up the other operators. If they do not currently exist, create * shells in order to get ObjectId's. */ - name[0] = commutatorName; - name[1] = negatorName; - name[2] = leftSortName; - name[3] = rightSortName; - for (j = 0; j < 4; ++j) + if (commutatorName) { - if (name[j]) - { - Oid otherLeftTypeId = InvalidOid; - Oid otherRightTypeId = InvalidOid; - Oid other_oid = InvalidOid; - bool otherDefined = false; + /* commutator has reversed arg types */ + commutatorId = get_other_operator(commutatorName, + rightTypeId, leftTypeId, + operatorName, operatorNamespace, + leftTypeId, rightTypeId, + true); + /* + * self-linkage to this operator; will fix below. Note + * that only self-linkage for commutation makes sense. + */ + if (!OidIsValid(commutatorId)) + selfCommutator = true; + } + else + commutatorId = InvalidOid; + values[i++] = ObjectIdGetDatum(commutatorId); /* oprcom */ - switch (j) - { - case 0: /* commutator has reversed arg types */ - otherLeftTypeId = rightTypeId; - otherRightTypeId = leftTypeId; - other_oid = OperatorGet(name[j], - otherLeftTypeId, - otherRightTypeId, - &otherDefined); - commutatorId = other_oid; - break; - case 1: /* negator has same arg types */ - otherLeftTypeId = leftTypeId; - otherRightTypeId = rightTypeId; - other_oid = OperatorGet(name[j], - otherLeftTypeId, - otherRightTypeId, - &otherDefined); - negatorId = other_oid; - break; - case 2: /* left sort op takes left-side data type */ - otherLeftTypeId = leftTypeId; - otherRightTypeId = leftTypeId; - other_oid = OperatorGet(name[j], - otherLeftTypeId, - otherRightTypeId, - &otherDefined); - break; - case 3: /* right sort op takes right-side data type */ - otherLeftTypeId = rightTypeId; - otherRightTypeId = rightTypeId; - other_oid = OperatorGet(name[j], - otherLeftTypeId, - otherRightTypeId, - &otherDefined); - break; - } + if (negatorName) + { + /* negator has same arg types */ + negatorId = get_other_operator(negatorName, + leftTypeId, rightTypeId, + operatorName, operatorNamespace, + leftTypeId, rightTypeId, + false); + } + else + negatorId = InvalidOid; + values[i++] = ObjectIdGetDatum(negatorId); /* oprnegate */ - if (OidIsValid(other_oid)) - { - /* other op already in catalogs */ - values[i++] = ObjectIdGetDatum(other_oid); - } - else if (strcmp(operatorName, name[j]) != 0 || - otherLeftTypeId != leftTypeId || - otherRightTypeId != rightTypeId) - { - /* not in catalogs, different from operator */ - other_oid = OperatorShellMake(name[j], - otherLeftTypeId, - otherRightTypeId); - if (!OidIsValid(other_oid)) - elog(ERROR, - "OperatorDef: can't create operator shell \"%s\"", - name[j]); - values[i++] = ObjectIdGetDatum(other_oid); - } - else - { - /* - * self-linkage to this operator; will fix below. Note - * that only self-linkage for commutation makes sense. - */ - if (j != 0) - elog(ERROR, - "operator cannot be its own negator or sort operator"); - selfCommutator = true; - values[i++] = ObjectIdGetDatum(InvalidOid); - } - } - else - { - /* other operator is omitted */ - values[i++] = ObjectIdGetDatum(InvalidOid); - } + if (leftSortName) + { + /* left sort op takes left-side data type */ + leftSortId = get_other_operator(leftSortName, + leftTypeId, leftTypeId, + operatorName, operatorNamespace, + leftTypeId, rightTypeId, + false); } + else + leftSortId = InvalidOid; + values[i++] = ObjectIdGetDatum(leftSortId); /* oprlsortop */ - /* last three fields were filled in above */ + if (rightSortName) + { + /* right sort op takes right-side data type */ + rightSortId = get_other_operator(rightSortName, + rightTypeId, rightTypeId, + operatorName, operatorNamespace, + leftTypeId, rightTypeId, + false); + } + else + rightSortId = InvalidOid; + values[i++] = ObjectIdGetDatum(rightSortId); /* oprrsortop */ + + if (ltCompareName) + { + /* comparator has same arg types */ + ltCompareId = get_other_operator(ltCompareName, + leftTypeId, rightTypeId, + operatorName, operatorNamespace, + leftTypeId, rightTypeId, + false); + } + else + ltCompareId = InvalidOid; + values[i++] = ObjectIdGetDatum(ltCompareId); /* oprltcmpop */ + + if (gtCompareName) + { + /* comparator has same arg types */ + gtCompareId = get_other_operator(gtCompareName, + leftTypeId, rightTypeId, + operatorName, operatorNamespace, + leftTypeId, rightTypeId, + false); + } + else + gtCompareId = InvalidOid; + values[i++] = ObjectIdGetDatum(gtCompareId); /* oprgtcmpop */ + + values[i++] = ObjectIdGetDatum(procOid); /* oprcode */ + values[i++] = ObjectIdGetDatum(restOid); /* oprrest */ + values[i++] = ObjectIdGetDatum(joinOid); /* oprjoin */ pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock); /* - * If we are adding to an operator shell, get its t_self + * If we are adding to an operator shell, update; else insert */ if (operatorObjectId) { - /* Make sure we can see the shell even if it is new in current cmd */ - CommandCounterIncrement(); - - ScanKeyEntryInitialize(&opKey[0], 0x0, - Anum_pg_operator_oprname, - F_NAMEEQ, - PointerGetDatum(operatorName)); - ScanKeyEntryInitialize(&opKey[1], 0x0, - Anum_pg_operator_oprleft, - F_OIDEQ, - ObjectIdGetDatum(leftTypeId)); - ScanKeyEntryInitialize(&opKey[2], 0x0, - Anum_pg_operator_oprright, - F_OIDEQ, - ObjectIdGetDatum(rightTypeId)); - - pg_operator_scan = heap_beginscan(pg_operator_desc, - 0, - SnapshotSelf, /* no cache? */ - 3, - opKey); - - tup = heap_getnext(pg_operator_scan, 0); - if (HeapTupleIsValid(tup)) - { - tup = heap_modifytuple(tup, - pg_operator_desc, - values, - nulls, - replaces); + tup = SearchSysCacheCopy(OPEROID, + ObjectIdGetDatum(operatorObjectId), + 0, 0, 0); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "OperatorDef: operator %u not found", + operatorObjectId); - simple_heap_update(pg_operator_desc, &tup->t_self, tup); - } - else - elog(ERROR, "OperatorDef: operator %u not found", operatorObjectId); + tup = heap_modifytuple(tup, + pg_operator_desc, + values, + nulls, + replaces); - heap_endscan(pg_operator_scan); + simple_heap_update(pg_operator_desc, &tup->t_self, tup); } else { @@ -676,6 +650,7 @@ OperatorDef(const char *operatorName, operatorObjectId = tup->t_data->t_oid; } + /* Must update the indexes in either case */ if (RelationGetForm(pg_operator_desc)->relhasindex) { Relation idescs[Num_pg_operator_indices]; @@ -705,7 +680,65 @@ OperatorDef(const char *operatorName, OperatorUpd(operatorObjectId, commutatorId, negatorId); } -/* ---------------------------------------------------------------- +/* + * Try to lookup another operator (commutator, etc) + * + * If not found, check to see if it is exactly the operator we are trying + * to define; if so, return InvalidOid. (Note that this case is only + * sensible for a commutator, so we error out otherwise.) If it is not + * the same operator, create a shell operator. + */ +static Oid +get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId, + const char *operatorName, Oid operatorNamespace, + Oid leftTypeId, Oid rightTypeId, bool isCommutator) +{ + Oid other_oid; + bool otherDefined; + char *otherName; + Oid otherNamespace; + + other_oid = OperatorLookup(otherOp, + otherLeftTypeId, + otherRightTypeId, + &otherDefined); + + if (OidIsValid(other_oid)) + { + /* other op already in catalogs */ + return other_oid; + } + + otherNamespace = QualifiedNameGetCreationNamespace(otherOp, + &otherName); + + if (strcmp(otherName, operatorName) == 0 && + otherNamespace == operatorNamespace && + otherLeftTypeId == leftTypeId && + otherRightTypeId == rightTypeId) + { + /* + * self-linkage to this operator; caller will fix later. Note + * that only self-linkage for commutation makes sense. + */ + if (!isCommutator) + elog(ERROR, "operator cannot be its own negator or sort operator"); + return InvalidOid; + } + + /* not in catalogs, different from operator, so make shell */ + other_oid = OperatorShellMake(otherName, + otherNamespace, + otherLeftTypeId, + otherRightTypeId); + if (!OidIsValid(other_oid)) + elog(ERROR, + "OperatorDef: can't create operator shell \"%s\"", + NameListToString(otherOp)); + return other_oid; +} + +/* * OperatorUpd * * For a given operator, look up its negator and commutator operators. @@ -713,19 +746,16 @@ OperatorDef(const char *operatorName, * (respectively) are empty, then use the new operator for neg or comm. * This solves a problem for users who need to insert two new operators * which are the negator or commutator of each other. - * ---------------------------------------------------------------- */ static void OperatorUpd(Oid baseId, Oid commId, Oid negId) { int i; Relation pg_operator_desc; - HeapScanDesc pg_operator_scan; HeapTuple tup; char nulls[Natts_pg_operator]; char replaces[Natts_pg_operator]; Datum values[Natts_pg_operator]; - ScanKeyData opKey[1]; for (i = 0; i < Natts_pg_operator; ++i) { @@ -734,8 +764,6 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) nulls[i] = ' '; } - pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock); - /* * check and update the commutator & negator, if necessary * @@ -743,18 +771,11 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) */ CommandCounterIncrement(); - ScanKeyEntryInitialize(&opKey[0], 0x0, - ObjectIdAttributeNumber, - F_OIDEQ, - ObjectIdGetDatum(commId)); - - pg_operator_scan = heap_beginscan(pg_operator_desc, - 0, - SnapshotSelf, /* no cache? */ - 1, - opKey); + pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock); - tup = heap_getnext(pg_operator_scan, 0); + tup = SearchSysCacheCopy(OPEROID, + ObjectIdGetDatum(commId), + 0, 0, 0); /* * if the commutator and negator are the same operator, do one update. @@ -765,13 +786,10 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) { if (HeapTupleIsValid(tup)) { - Form_pg_operator t; + Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup); - t = (Form_pg_operator) GETSTRUCT(tup); - if (!OidIsValid(t->oprcom) - || !OidIsValid(t->oprnegate)) + if (!OidIsValid(t->oprcom) || !OidIsValid(t->oprnegate)) { - if (!OidIsValid(t->oprnegate)) { values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId); @@ -802,7 +820,6 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) } } } - heap_endscan(pg_operator_scan); heap_close(pg_operator_desc, RowExclusiveLock); @@ -816,6 +833,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) { values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId); replaces[Anum_pg_operator_oprcom - 1] = 'r'; + tup = heap_modifytuple(tup, pg_operator_desc, values, @@ -837,23 +855,18 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) replaces[Anum_pg_operator_oprcom - 1] = ' '; } - heap_endscan(pg_operator_scan); - /* check and update the negator, if necessary */ - opKey[0].sk_argument = ObjectIdGetDatum(negId); - pg_operator_scan = heap_beginscan(pg_operator_desc, - 0, - SnapshotSelf, /* no cache? */ - 1, - opKey); + tup = SearchSysCacheCopy(OPEROID, + ObjectIdGetDatum(negId), + 0, 0, 0); - tup = heap_getnext(pg_operator_scan, 0); if (HeapTupleIsValid(tup) && !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate))) { values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId); replaces[Anum_pg_operator_oprnegate - 1] = 'r'; + tup = heap_modifytuple(tup, pg_operator_desc, values, @@ -872,79 +885,5 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) } } - heap_endscan(pg_operator_scan); - heap_close(pg_operator_desc, RowExclusiveLock); } - - -/* ---------------------------------------------------------------- - * OperatorCreate - * - * This is now just an interface procedure for OperatorDef ... - * - * "X" indicates an optional argument (i.e. one that can be NULL or 0) - * operatorName; -- operator name - * leftTypeId; -- X left type ID - * rightTypeId; -- X right type ID - * procedureName; -- procedure for operator - * precedence; -- operator precedence - * isLeftAssociative; -- operator is left associative - * commutatorName; -- X commutator operator name - * negatorName; -- X negator operator name - * restrictionName; -- X restriction sel. procedure - * joinName; -- X join sel. procedure - * canHash; -- hash join can be used with this operator - * leftSortName; -- X left sort operator (for merge join) - * rightSortName; -- X right sort operator (for merge join) - */ -void -OperatorCreate(const char *operatorName, - Oid leftTypeId, - Oid rightTypeId, - const char *procedureName, - uint16 precedence, - bool isLeftAssociative, - const char *commutatorName, - const char *negatorName, - const char *restrictionName, - const char *joinName, - bool canHash, - const char *leftSortName, - const char *rightSortName) -{ - if (!OidIsValid(leftTypeId) && !OidIsValid(rightTypeId)) - elog(ERROR, "at least one of leftarg or rightarg must be specified"); - - if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId))) - { - /* If it's not a binary op, these things mustn't be set: */ - if (commutatorName) - elog(ERROR, "only binary operators can have commutators"); - if (joinName) - elog(ERROR, "only binary operators can have join selectivity"); - if (canHash) - elog(ERROR, "only binary operators can hash"); - if (leftSortName || rightSortName) - elog(ERROR, "only binary operators can have sort links"); - } - - /* - * Use OperatorDef() to define the specified operator and also create - * shells for the operator's associated operators if they don't - * already exist. - */ - OperatorDef(operatorName, - leftTypeId, - rightTypeId, - makeList1(makeString((char*) procedureName)), /* XXX */ - precedence, - isLeftAssociative, - commutatorName, - negatorName, - restrictionName ? makeList1(makeString((char*) restrictionName)) : NIL, /* XXX */ - joinName ? makeList1(makeString((char*) joinName)) : NIL, /* XXX */ - canHash, - leftSortName, - rightSortName); -} diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index e36f21273d..f4c8e6919e 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.31 2002/04/12 20:38:20 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.32 2002/04/16 23:08:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -398,7 +398,7 @@ examine_attribute(Relation onerel, int attnum) return NULL; /* If column has no "=" operator, we can't do much of anything */ - func_operator = compatible_oper("=", + func_operator = compatible_oper(makeList1(makeString("=")), attr->atttypid, attr->atttypid, true); @@ -436,7 +436,7 @@ examine_attribute(Relation onerel, int attnum) stats->eqfunc = eqfunc; /* Is there a "<" operator with suitable semantics? */ - func_operator = compatible_oper("<", + func_operator = compatible_oper(makeList1(makeString("<")), attr->atttypid, attr->atttypid, true); diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index b7de77067d..3eb9a5eb67 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -7,7 +7,7 @@ * Copyright (c) 1999-2001, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.40 2002/04/11 19:59:57 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.41 2002/04/16 23:08:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -28,6 +28,7 @@ #include "commands/comment.h" #include "miscadmin.h" #include "parser/parse_func.h" +#include "parser/parse_oper.h" #include "parser/parse_type.h" #include "parser/parse.h" #include "utils/acl.h" @@ -53,7 +54,7 @@ static void CommentRule(List *qualname, char *comment); static void CommentType(List *typename, char *comment); static void CommentAggregate(List *aggregate, List *arguments, char *comment); static void CommentProc(List *function, List *arguments, char *comment); -static void CommentOperator(List *qualname, List *arguments, char *comment); +static void CommentOperator(List *opername, List *arguments, char *comment); static void CommentTrigger(List *qualname, char *comment); @@ -643,63 +644,29 @@ CommentProc(List *function, List *arguments, char *comment) * to be visible for both operator and function. */ static void -CommentOperator(List *qualname, List *arguments, char *comment) +CommentOperator(List *opername, List *arguments, char *comment) { - char *opername = strVal(lfirst(qualname)); /* XXX */ TypeName *typenode1 = (TypeName *) lfirst(arguments); TypeName *typenode2 = (TypeName *) lsecond(arguments); - char oprtype = 0; - Form_pg_operator data; - HeapTuple optuple; - Oid oid, - leftoid = InvalidOid, - rightoid = InvalidOid; - - /* Attempt to fetch the left type oid, if specified */ - if (typenode1 != NULL) - leftoid = typenameTypeId(typenode1); - - /* Attempt to fetch the right type oid, if specified */ - if (typenode2 != NULL) - rightoid = typenameTypeId(typenode2); - - /* Determine operator type */ - - if (OidIsValid(leftoid) && (OidIsValid(rightoid))) - oprtype = 'b'; - else if (OidIsValid(leftoid)) - oprtype = 'r'; - else if (OidIsValid(rightoid)) - oprtype = 'l'; - else - elog(ERROR, "operator '%s' is of an illegal type'", opername); - - /* Attempt to fetch the operator oid */ + Oid oid; - optuple = SearchSysCache(OPERNAME, - PointerGetDatum(opername), - ObjectIdGetDatum(leftoid), - ObjectIdGetDatum(rightoid), - CharGetDatum(oprtype)); - if (!HeapTupleIsValid(optuple)) - elog(ERROR, "operator '%s' does not exist", opername); + /* Look up the operator */ - oid = optuple->t_data->t_oid; + oid = LookupOperNameTypeNames(opername, typenode1, typenode2, + "CommentOperator"); /* Valid user's ability to comment on this operator */ if (!pg_oper_ownercheck(oid, GetUserId())) elog(ERROR, "you are not permitted to comment on operator '%s'", - opername); + NameListToString(opername)); /* Get the procedure associated with the operator */ - data = (Form_pg_operator) GETSTRUCT(optuple); - oid = data->oprcode; + oid = get_opcode(oid); if (oid == InvalidOid) - elog(ERROR, "operator '%s' does not have an underlying function", opername); - - ReleaseSysCache(optuple); + elog(ERROR, "operator '%s' does not have an underlying function", + NameListToString(opername)); /* Call CreateComments() to create/drop the comments */ diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c index 54f48928b4..ffc35ea1ae 100644 --- a/src/backend/commands/operatorcmds.c +++ b/src/backend/commands/operatorcmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/operatorcmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/operatorcmds.c,v 1.2 2002/04/16 23:08:10 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -41,6 +41,7 @@ #include "commands/comment.h" #include "commands/defrem.h" #include "miscadmin.h" +#include "parser/parse_oper.h" #include "parser/parse_type.h" #include "utils/acl.h" #include "utils/syscache.h" @@ -59,23 +60,26 @@ DefineOperator(List *names, List *parameters) { char *oprName; Oid oprNamespace; - uint16 precedence = 0; /* operator precedence */ - bool canHash = false; /* operator hashes */ + uint16 precedence = 0; /* operator precedence */ + bool canHash = false; /* operator hashes */ + bool canMerge = false; /* operator merges */ bool isLeftAssociative = true; /* operator is left * associative */ - char *functionName = NULL; /* function for operator */ + List *functionName = NIL; /* function for operator */ TypeName *typeName1 = NULL; /* first type name */ TypeName *typeName2 = NULL; /* second type name */ Oid typeId1 = InvalidOid; /* types converted to OID */ Oid typeId2 = InvalidOid; - char *commutatorName = NULL; /* optional commutator operator + List *commutatorName = NIL; /* optional commutator operator * name */ - char *negatorName = NULL; /* optional negator operator name */ - char *restrictionName = NULL; /* optional restrict. sel. + List *negatorName = NIL; /* optional negator operator name */ + List *restrictionName = NIL; /* optional restrict. sel. * procedure */ - char *joinName = NULL; /* optional join sel. procedure name */ - char *sortName1 = NULL; /* optional first sort operator */ - char *sortName2 = NULL; /* optional second sort operator */ + List *joinName = NIL; /* optional join sel. procedure */ + List *leftSortName = NIL; /* optional left sort operator */ + List *rightSortName = NIL; /* optional right sort operator */ + List *ltCompareName = NIL; /* optional < compare operator */ + List *gtCompareName = NIL; /* optional > compare operator */ List *pl; /* Convert list of names to a name and namespace */ @@ -101,7 +105,7 @@ DefineOperator(List *names, List *parameters) elog(ERROR, "setof type not implemented for rightarg"); } else if (strcasecmp(defel->defname, "procedure") == 0) - functionName = defGetString(defel); + functionName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "precedence") == 0) { /* NOT IMPLEMENTED (never worked in v4.2) */ @@ -113,19 +117,25 @@ DefineOperator(List *names, List *parameters) elog(NOTICE, "CREATE OPERATOR: associativity not implemented"); } else if (strcasecmp(defel->defname, "commutator") == 0) - commutatorName = defGetString(defel); + commutatorName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "negator") == 0) - negatorName = defGetString(defel); + negatorName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "restrict") == 0) - restrictionName = defGetString(defel); + restrictionName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "join") == 0) - joinName = defGetString(defel); + joinName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "hashes") == 0) canHash = TRUE; + else if (strcasecmp(defel->defname, "merges") == 0) + canMerge = TRUE; else if (strcasecmp(defel->defname, "sort1") == 0) - sortName1 = defGetString(defel); + leftSortName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "sort2") == 0) - sortName2 = defGetString(defel); + rightSortName = defGetQualifiedName(defel); + else if (strcasecmp(defel->defname, "ltcmp") == 0) + ltCompareName = defGetQualifiedName(defel); + else if (strcasecmp(defel->defname, "gtcmp") == 0) + gtCompareName = defGetQualifiedName(defel); else { elog(WARNING, "DefineOperator: attribute \"%s\" not recognized", @@ -136,7 +146,7 @@ DefineOperator(List *names, List *parameters) /* * make sure we have our required definitions */ - if (functionName == NULL) + if (functionName == NIL) elog(ERROR, "Define: \"procedure\" unspecified"); /* Transform type names to type OIDs */ @@ -146,9 +156,30 @@ DefineOperator(List *names, List *parameters) typeId2 = typenameTypeId(typeName2); /* + * If any of the mergejoin support operators were given, then canMerge + * is implicit. If canMerge is specified or implicit, fill in default + * operator names for any missing mergejoin support operators. + */ + if (leftSortName || rightSortName || ltCompareName || gtCompareName) + canMerge = true; + + if (canMerge) + { + if (!leftSortName) + leftSortName = makeList1(makeString("<")); + if (!rightSortName) + rightSortName = makeList1(makeString("<")); + if (!ltCompareName) + ltCompareName = makeList1(makeString("<")); + if (!gtCompareName) + gtCompareName = makeList1(makeString(">")); + } + + /* * now have OperatorCreate do all the work.. */ OperatorCreate(oprName, /* operator name */ + oprNamespace, /* namespace */ typeId1, /* left type id */ typeId2, /* right type id */ functionName, /* function for operator */ @@ -161,9 +192,10 @@ DefineOperator(List *names, List *parameters) * procedure */ joinName, /* optional join sel. procedure name */ canHash, /* operator hashes */ - sortName1, /* optional first sort operator */ - sortName2); /* optional second sort operator */ - + leftSortName, /* optional left sort operator */ + rightSortName, /* optional right sort operator */ + ltCompareName, /* optional < comparison op */ + gtCompareName); /* optional < comparison op */ } @@ -178,70 +210,36 @@ DefineOperator(List *names, List *parameters) * ... */ void -RemoveOperator(char *operatorName, /* operator name */ +RemoveOperator(List *operatorName, /* operator name */ TypeName *typeName1, /* left argument type name */ TypeName *typeName2) /* right argument type name */ { + Oid operOid; Relation relation; HeapTuple tup; - Oid typeId1 = InvalidOid; - Oid typeId2 = InvalidOid; - char oprtype; - if (typeName1) - typeId1 = typenameTypeId(typeName1); + operOid = LookupOperNameTypeNames(operatorName, typeName1, typeName2, + "RemoveOperator"); - if (typeName2) - typeId2 = typenameTypeId(typeName2); + relation = heap_openr(OperatorRelationName, RowExclusiveLock); - if (OidIsValid(typeId1) && OidIsValid(typeId2)) - oprtype = 'b'; - else if (OidIsValid(typeId1)) - oprtype = 'r'; - else - oprtype = 'l'; + tup = SearchSysCacheCopy(OPEROID, + ObjectIdGetDatum(operOid), + 0, 0, 0); - relation = heap_openr(OperatorRelationName, RowExclusiveLock); + if (!HeapTupleIsValid(tup)) /* should not happen */ + elog(ERROR, "RemoveOperator: failed to find tuple for operator '%s'", + NameListToString(operatorName)); - tup = SearchSysCacheCopy(OPERNAME, - PointerGetDatum(operatorName), - ObjectIdGetDatum(typeId1), - ObjectIdGetDatum(typeId2), - CharGetDatum(oprtype)); + if (!pg_oper_ownercheck(operOid, GetUserId())) + elog(ERROR, "RemoveOperator: operator '%s': permission denied", + NameListToString(operatorName)); - if (HeapTupleIsValid(tup)) - { - if (!pg_oper_ownercheck(tup->t_data->t_oid, GetUserId())) - elog(ERROR, "RemoveOperator: operator '%s': permission denied", - operatorName); + /* Delete any comments associated with this operator */ + DeleteComments(operOid, RelationGetRelid(relation)); - /* Delete any comments associated with this operator */ - DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation)); + simple_heap_delete(relation, &tup->t_self); - simple_heap_delete(relation, &tup->t_self); - } - else - { - if (OidIsValid(typeId1) && OidIsValid(typeId2)) - { - elog(ERROR, "RemoveOperator: binary operator '%s' taking '%s' and '%s' does not exist", - operatorName, - TypeNameToString(typeName1), - TypeNameToString(typeName2)); - } - else if (OidIsValid(typeId1)) - { - elog(ERROR, "RemoveOperator: right unary operator '%s' taking '%s' does not exist", - operatorName, - TypeNameToString(typeName1)); - } - else - { - elog(ERROR, "RemoveOperator: left unary operator '%s' taking '%s' does not exist", - operatorName, - TypeNameToString(typeName2)); - } - } heap_freetuple(tup); heap_close(relation, RowExclusiveLock); } diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 3ccbcd8efc..6ded8c5604 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -46,7 +46,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.81 2002/04/11 19:59:58 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.82 2002/04/16 23:08:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -925,7 +925,8 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent) &peraggstate->inputtypeLen, &peraggstate->inputtypeByVal); - eq_function = compatible_oper_funcid("=", inputType, inputType, + eq_function = compatible_oper_funcid(makeList1(makeString("=")), + inputType, inputType, true); if (!OidIsValid(eq_function)) elog(ERROR, "Unable to identify an equality operator for type '%s'", diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c index e3aea3b789..881dfa4f1b 100644 --- a/src/backend/executor/nodeGroup.c +++ b/src/backend/executor/nodeGroup.c @@ -15,7 +15,7 @@ * locate group boundaries. * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.44 2001/10/25 05:49:28 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.45 2002/04/16 23:08:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -490,7 +490,8 @@ execTuplesMatchPrepare(TupleDesc tupdesc, Oid typid = tupdesc->attrs[att - 1]->atttypid; Oid eq_function; - eq_function = compatible_oper_funcid("=", typid, typid, true); + eq_function = compatible_oper_funcid(makeList1(makeString("=")), + typid, typid, true); if (!OidIsValid(eq_function)) elog(ERROR, "Unable to identify an equality operator for type '%s'", typeidTypeName(typid)); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 5eed3a33f5..40e1dea79e 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.177 2002/04/11 19:59:59 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.178 2002/04/16 23:08:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1526,8 +1526,7 @@ _copyAExpr(A_Expr *from) A_Expr *newnode = makeNode(A_Expr); newnode->oper = from->oper; - if (from->opname) - newnode->opname = pstrdup(from->opname); + Node_Copy(from, newnode, name); Node_Copy(from, newnode, lexpr); Node_Copy(from, newnode, rexpr); @@ -1648,8 +1647,7 @@ _copySortGroupBy(SortGroupBy *from) { SortGroupBy *newnode = makeNode(SortGroupBy); - if (from->useOp) - newnode->useOp = pstrdup(from->useOp); + Node_Copy(from, newnode, useOp); Node_Copy(from, newnode, node); return newnode; @@ -2128,7 +2126,7 @@ _copyRemoveOperStmt(RemoveOperStmt *from) { RemoveOperStmt *newnode = makeNode(RemoveOperStmt); - newnode->opname = pstrdup(from->opname); + Node_Copy(from, newnode, opname); Node_Copy(from, newnode, args); return newnode; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index cafd77a822..245d72fc01 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -20,7 +20,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.125 2002/04/11 19:59:59 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.126 2002/04/16 23:08:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -969,7 +969,7 @@ _equalRemoveFuncStmt(RemoveFuncStmt *a, RemoveFuncStmt *b) static bool _equalRemoveOperStmt(RemoveOperStmt *a, RemoveOperStmt *b) { - if (!equalstr(a->opname, b->opname)) + if (!equal(a->opname, b->opname)) return false; if (!equal(a->args, b->args)) return false; @@ -1400,7 +1400,7 @@ _equalAExpr(A_Expr *a, A_Expr *b) { if (a->oper != b->oper) return false; - if (!equalstr(a->opname, b->opname)) + if (!equal(a->name, b->name)) return false; if (!equal(a->lexpr, b->lexpr)) return false; @@ -1520,7 +1520,7 @@ _equalTypeCast(TypeCast *a, TypeCast *b) static bool _equalSortGroupBy(SortGroupBy *a, SortGroupBy *b) { - if (!equalstr(a->useOp, b->useOp)) + if (!equal(a->useOp, b->useOp)) return false; if (!equal(a->node, b->node)) return false; diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index 6d649ba9d1..65f4ffcca3 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.30 2002/03/29 19:06:09 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.31 2002/04/16 23:08:10 tgl Exp $ */ #include "postgres.h" @@ -17,6 +17,39 @@ /* + * makeA_Expr - + * makes an A_Expr node + */ +A_Expr * +makeA_Expr(int oper, List *name, Node *lexpr, Node *rexpr) +{ + A_Expr *a = makeNode(A_Expr); + + a->oper = oper; + a->name = name; + a->lexpr = lexpr; + a->rexpr = rexpr; + return a; +} + +/* + * makeSimpleA_Expr - + * As above, given a simple (unqualified) operator name + */ +A_Expr * +makeSimpleA_Expr(int oper, const char *name, + Node *lexpr, Node *rexpr) +{ + A_Expr *a = makeNode(A_Expr); + + a->oper = oper; + a->name = makeList1(makeString((char *) name)); + a->lexpr = lexpr; + a->rexpr = rexpr; + return a; +} + +/* * makeOper - * creates an Oper node */ diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 09a3eb767f..65a501c429 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -5,7 +5,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.154 2002/04/11 19:59:59 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.155 2002/04/16 23:08:10 tgl Exp $ * * NOTES * Every (plan) node in POSTGRES has an associated "out" routine which @@ -1285,7 +1285,7 @@ _outAExpr(StringInfo str, A_Expr *node) appendStringInfo(str, "NOT "); break; case OP: - _outToken(str, node->opname); + _outNode(str, node->name); appendStringInfo(str, " "); break; default: diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 60a7dd9503..21599b08bd 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.115 2002/04/05 00:31:26 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.116 2002/04/16 23:08:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,7 @@ #include "access/nbtree.h" #include "catalog/catname.h" #include "catalog/pg_amop.h" +#include "catalog/pg_namespace.h" #include "catalog/pg_operator.h" #include "executor/executor.h" #include "nodes/makefuncs.h" @@ -911,7 +912,8 @@ indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left) * operator, but in practice that seems pretty unlikely for * binary-compatible types.) */ - new_op = compatible_oper_opid(opname, indexkeytype, indexkeytype, true); + new_op = compatible_oper_opid(makeList1(makeString(opname)), + indexkeytype, indexkeytype, true); if (OidIsValid(new_op)) { @@ -2143,14 +2145,15 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop) */ /* See if there is a binary op of the given name for the given datatype */ +/* NB: we assume that only built-in system operators are searched for */ static Oid find_operator(const char *opname, Oid datatype) { - return GetSysCacheOid(OPERNAME, + return GetSysCacheOid(OPERNAMENSP, PointerGetDatum(opname), ObjectIdGetDatum(datatype), ObjectIdGetDatum(datatype), - CharGetDatum('b')); + ObjectIdGetDatum(PG_CATALOG_NAMESPACE)); } /* diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 2c9acc73b7..39ac5ba886 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.67 2002/03/12 00:51:45 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.68 2002/04/16 23:08:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -740,7 +740,8 @@ process_implied_equality(Query *root, Node *item1, Node *item2, */ ltype = exprType(item1); rtype = exprType(item2); - eq_operator = compatible_oper("=", ltype, rtype, true); + eq_operator = compatible_oper(makeList1(makeString("=")), + ltype, rtype, true); if (!HeapTupleIsValid(eq_operator)) { /* diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 94a198473d..a67eb5d8e5 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.50 2001/11/30 19:24:15 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.51 2002/04/16 23:08:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -284,9 +284,9 @@ make_subplan(SubLink *slink) * Note: we use make_operand in case runtime type conversion * function calls must be inserted for this operator! */ - left = make_operand("", lefthand, + left = make_operand(lefthand, exprType(lefthand), opform->oprleft); - right = make_operand("", (Node *) prm, + right = make_operand((Node *) prm, prm->paramtype, opform->oprright); ReleaseSysCache(tup); @@ -433,9 +433,9 @@ make_subplan(SubLink *slink) * Note: we use make_operand in case runtime type conversion * function calls must be inserted for this operator! */ - left = make_operand("", lefthand, + left = make_operand(lefthand, exprType(lefthand), opform->oprleft); - right = make_operand("", (Node *) con, + right = make_operand((Node *) con, con->consttype, opform->oprright); ReleaseSysCache(tup); diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index f71f40829c..6a68adfff3 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.229 2002/04/12 19:11:49 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.230 2002/04/16 23:08:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1460,11 +1460,13 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt) { /* * fktypoid[i] is the foreign key table's i'th element's type - * oid pktypoid[i] is the primary key table's i'th element's - * type oid We let oper() do our work for us, including - * elog(ERROR) if the types don't compare with = + * pktypoid[i] is the primary key table's i'th element's type + * + * We let oper() do our work for us, including elog(ERROR) if + * the types don't compare with = */ - Operator o = oper("=", fktypoid[i], pktypoid[i], false); + Operator o = oper(makeList1(makeString("=")), + fktypoid[i], pktypoid[i], false); ReleaseSysCache(o); } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 3488fb0762..26b1be11d8 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.301 2002/04/09 20:35:51 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.302 2002/04/16 23:08:11 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -82,11 +82,10 @@ static int pfunc_num_args; */ /*#define __YYSCLASS*/ -static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); static Node *makeTypeCast(Node *arg, TypeName *typename); static Node *makeStringConst(char *str, TypeName *typename); static Node *makeFloatConst(char *str); -static Node *makeRowExpr(char *opr, List *largs, List *rargs); +static Node *makeRowExpr(List *opr, List *largs, List *rargs); static SelectStmt *findLeftmostSelect(SelectStmt *node); static void insertSelectOptions(SelectStmt *stmt, List *sortClause, List *forUpdate, @@ -177,13 +176,13 @@ static bool set_name_needs_quotes(const char *name); database_name, access_method_clause, access_method, attr_name, class, index_name, name, function_name, file_name -%type <list> func_name, handler_name +%type <list> func_name, handler_name, qual_Op, qual_all_Op, OptUseOp %type <range> qualified_name, OptConstrFromTable %type <str> opt_id, all_Op, MathOp, opt_name, - OptUseOp, opt_class, SpecialRuleRelation + opt_class, SpecialRuleRelation %type <str> opt_level, opt_encoding %type <node> grantee @@ -202,7 +201,7 @@ static bool set_name_needs_quotes(const char *name); opt_column_list, columnList, opt_name_list, sort_clause, sortby_list, index_params, index_list, name_list, from_clause, from_list, opt_array_bounds, qualified_name_list, - any_name, any_name_list, expr_list, dotted_name, attrs, + any_name, any_name_list, any_operator, expr_list, dotted_name, attrs, target_list, update_target_list, insert_column_list, insert_target_list, def_list, opt_indirection, group_clause, TriggerFuncArgs, @@ -404,7 +403,7 @@ static bool set_name_needs_quotes(const char *name); %nonassoc BETWEEN %nonassoc IN %left POSTFIXOP /* dummy for postfix Op rules */ -%left Op /* multi-character ops and user-defined operators */ +%left Op OPERATOR /* multi-character ops and user-defined operators */ %nonassoc NOTNULL %nonassoc ISNULL %nonassoc IS NULL_P TRUE_P FALSE_P UNKNOWN /* sets precedence for IS NULL, etc */ @@ -2086,11 +2085,11 @@ DefineStmt: CREATE AGGREGATE func_name definition n->definition = $4; $$ = (Node *)n; } - | CREATE OPERATOR all_Op definition + | CREATE OPERATOR any_operator definition { DefineStmt *n = makeNode(DefineStmt); n->defType = OPERATOR; - n->defnames = makeList1(makeString($3)); /* XXX */ + n->defnames = $3; n->definition = $4; $$ = (Node *)n; } @@ -2227,11 +2226,11 @@ CommentStmt: COMMENT ON comment_type any_name IS comment_text n->comment = $7; $$ = (Node *) n; } - | COMMENT ON OPERATOR all_Op '(' oper_argtypes ')' IS comment_text + | COMMENT ON OPERATOR any_operator '(' oper_argtypes ')' IS comment_text { CommentStmt *n = makeNode(CommentStmt); n->objtype = OPERATOR; - n->objname = makeList1(makeString($4)); /* XXX */ + n->objname = $4; n->objargs = $6; n->comment = $9; $$ = (Node *) n; @@ -2812,7 +2811,7 @@ aggr_argtype: Typename { $$ = $1; } | '*' { $$ = NULL; } ; -RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')' +RemoveOperStmt: DROP OPERATOR any_operator '(' oper_argtypes ')' { RemoveOperStmt *n = makeNode(RemoveOperStmt); n->opname = $3; @@ -2833,6 +2832,12 @@ oper_argtypes: Typename { $$ = makeList2($1, NULL); } ; +any_operator: all_Op + { $$ = makeList1(makeString($1)); } + | ColId '.' any_operator + { $$ = lcons(makeString($1), $3); } + ; + /***************************************************************************** * @@ -3831,10 +3836,14 @@ sortby: a_expr OptUseOp } ; -OptUseOp: USING all_Op { $$ = $2; } - | ASC { $$ = "<"; } - | DESC { $$ = ">"; } - | /*EMPTY*/ { $$ = "<"; /*default*/ } +OptUseOp: USING qual_all_Op + { $$ = $2; } + | ASC + { $$ = makeList1(makeString("<")); } + | DESC + { $$ = makeList1(makeString(">")); } + | /*EMPTY*/ + { $$ = makeList1(makeString("<")); /*default*/ } ; @@ -4593,7 +4602,7 @@ row_expr: '(' row_descriptor ')' IN select_with_parens { SubLink *n = makeNode(SubLink); n->lefthand = $2; - n->oper = (List *) makeA_Expr(OP, "=", NULL, NULL); + n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL); n->useor = FALSE; n->subLinkType = ANY_SUBLINK; n->subselect = $5; @@ -4603,18 +4612,18 @@ row_expr: '(' row_descriptor ')' IN select_with_parens { SubLink *n = makeNode(SubLink); n->lefthand = $2; - n->oper = (List *) makeA_Expr(OP, "<>", NULL, NULL); + n->oper = (List *) makeSimpleA_Expr(OP, "<>", NULL, NULL); n->useor = TRUE; n->subLinkType = ALL_SUBLINK; n->subselect = $6; $$ = (Node *)n; } - | '(' row_descriptor ')' all_Op sub_type select_with_parens + | '(' row_descriptor ')' qual_all_Op sub_type select_with_parens %prec Op { SubLink *n = makeNode(SubLink); n->lefthand = $2; n->oper = (List *) makeA_Expr(OP, $4, NULL, NULL); - if (strcmp($4, "<>") == 0) + if (strcmp(strVal(llast($4)), "<>") == 0) n->useor = TRUE; else n->useor = FALSE; @@ -4622,12 +4631,12 @@ row_expr: '(' row_descriptor ')' IN select_with_parens n->subselect = $6; $$ = (Node *)n; } - | '(' row_descriptor ')' all_Op select_with_parens + | '(' row_descriptor ')' qual_all_Op select_with_parens %prec Op { SubLink *n = makeNode(SubLink); n->lefthand = $2; n->oper = (List *) makeA_Expr(OP, $4, NULL, NULL); - if (strcmp($4, "<>") == 0) + if (strcmp(strVal(llast($4)), "<>") == 0) n->useor = TRUE; else n->useor = FALSE; @@ -4635,7 +4644,7 @@ row_expr: '(' row_descriptor ')' IN select_with_parens n->subselect = $5; $$ = (Node *)n; } - | '(' row_descriptor ')' all_Op '(' row_descriptor ')' + | '(' row_descriptor ')' qual_all_Op '(' row_descriptor ')' %prec Op { $$ = makeRowExpr($4, $2, $6); } @@ -4696,6 +4705,18 @@ MathOp: '+' { $$ = "+"; } | '=' { $$ = "="; } ; +qual_Op: Op + { $$ = makeList1(makeString($1)); } + | OPERATOR '(' any_operator ')' + { $$ = $3; } + ; + +qual_all_Op: all_Op + { $$ = makeList1(makeString($1)); } + | OPERATOR '(' any_operator ')' + { $$ = $3; } + ; + /* * General expressions * This is the heart of the expression syntax. @@ -4735,52 +4756,52 @@ a_expr: c_expr * also to b_expr and to the MathOp list above. */ | '+' a_expr %prec UMINUS - { $$ = makeA_Expr(OP, "+", NULL, $2); } + { $$ = (Node *) makeSimpleA_Expr(OP, "+", NULL, $2); } | '-' a_expr %prec UMINUS { $$ = doNegate($2); } | '%' a_expr - { $$ = makeA_Expr(OP, "%", NULL, $2); } + { $$ = (Node *) makeSimpleA_Expr(OP, "%", NULL, $2); } | '^' a_expr - { $$ = makeA_Expr(OP, "^", NULL, $2); } + { $$ = (Node *) makeSimpleA_Expr(OP, "^", NULL, $2); } | a_expr '%' - { $$ = makeA_Expr(OP, "%", $1, NULL); } + { $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, NULL); } | a_expr '^' - { $$ = makeA_Expr(OP, "^", $1, NULL); } + { $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, NULL); } | a_expr '+' a_expr - { $$ = makeA_Expr(OP, "+", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "+", $1, $3); } | a_expr '-' a_expr - { $$ = makeA_Expr(OP, "-", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "-", $1, $3); } | a_expr '*' a_expr - { $$ = makeA_Expr(OP, "*", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "*", $1, $3); } | a_expr '/' a_expr - { $$ = makeA_Expr(OP, "/", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "/", $1, $3); } | a_expr '%' a_expr - { $$ = makeA_Expr(OP, "%", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, $3); } | a_expr '^' a_expr - { $$ = makeA_Expr(OP, "^", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, $3); } | a_expr '<' a_expr - { $$ = makeA_Expr(OP, "<", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "<", $1, $3); } | a_expr '>' a_expr - { $$ = makeA_Expr(OP, ">", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, ">", $1, $3); } | a_expr '=' a_expr - { $$ = makeA_Expr(OP, "=", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "=", $1, $3); } - | a_expr Op a_expr - { $$ = makeA_Expr(OP, $2, $1, $3); } - | Op a_expr - { $$ = makeA_Expr(OP, $1, NULL, $2); } - | a_expr Op %prec POSTFIXOP - { $$ = makeA_Expr(OP, $2, $1, NULL); } + | a_expr qual_Op a_expr %prec Op + { $$ = (Node *) makeA_Expr(OP, $2, $1, $3); } + | qual_Op a_expr %prec Op + { $$ = (Node *) makeA_Expr(OP, $1, NULL, $2); } + | a_expr qual_Op %prec POSTFIXOP + { $$ = (Node *) makeA_Expr(OP, $2, $1, NULL); } | a_expr AND a_expr - { $$ = makeA_Expr(AND, NULL, $1, $3); } + { $$ = (Node *) makeA_Expr(AND, NIL, $1, $3); } | a_expr OR a_expr - { $$ = makeA_Expr(OR, NULL, $1, $3); } + { $$ = (Node *) makeA_Expr(OR, NIL, $1, $3); } | NOT a_expr - { $$ = makeA_Expr(NOT, NULL, NULL, $2); } + { $$ = (Node *) makeA_Expr(NOT, NIL, NULL, $2); } | a_expr LIKE a_expr - { $$ = makeA_Expr(OP, "~~", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "~~", $1, $3); } | a_expr LIKE a_expr ESCAPE a_expr { FuncCall *n = makeNode(FuncCall); @@ -4788,10 +4809,10 @@ a_expr: c_expr n->args = makeList2($3, $5); n->agg_star = FALSE; n->agg_distinct = FALSE; - $$ = makeA_Expr(OP, "~~", $1, (Node *) n); + $$ = (Node *) makeSimpleA_Expr(OP, "~~", $1, (Node *) n); } | a_expr NOT LIKE a_expr - { $$ = makeA_Expr(OP, "!~~", $1, $4); } + { $$ = (Node *) makeSimpleA_Expr(OP, "!~~", $1, $4); } | a_expr NOT LIKE a_expr ESCAPE a_expr { FuncCall *n = makeNode(FuncCall); @@ -4799,10 +4820,10 @@ a_expr: c_expr n->args = makeList2($4, $6); n->agg_star = FALSE; n->agg_distinct = FALSE; - $$ = makeA_Expr(OP, "!~~", $1, (Node *) n); + $$ = (Node *) makeSimpleA_Expr(OP, "!~~", $1, (Node *) n); } | a_expr ILIKE a_expr - { $$ = makeA_Expr(OP, "~~*", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "~~*", $1, $3); } | a_expr ILIKE a_expr ESCAPE a_expr { FuncCall *n = makeNode(FuncCall); @@ -4810,10 +4831,10 @@ a_expr: c_expr n->args = makeList2($3, $5); n->agg_star = FALSE; n->agg_distinct = FALSE; - $$ = makeA_Expr(OP, "~~*", $1, (Node *) n); + $$ = (Node *) makeSimpleA_Expr(OP, "~~*", $1, (Node *) n); } | a_expr NOT ILIKE a_expr - { $$ = makeA_Expr(OP, "!~~*", $1, $4); } + { $$ = (Node *) makeSimpleA_Expr(OP, "!~~*", $1, $4); } | a_expr NOT ILIKE a_expr ESCAPE a_expr { FuncCall *n = makeNode(FuncCall); @@ -4821,7 +4842,7 @@ a_expr: c_expr n->args = makeList2($4, $6); n->agg_star = FALSE; n->agg_distinct = FALSE; - $$ = makeA_Expr(OP, "!~~*", $1, (Node *) n); + $$ = (Node *) makeSimpleA_Expr(OP, "!~~*", $1, (Node *) n); } /* NullTest clause * Define SQL92-style Null test clause. @@ -4915,15 +4936,15 @@ a_expr: c_expr } | a_expr BETWEEN b_expr AND b_expr %prec BETWEEN { - $$ = makeA_Expr(AND, NULL, - makeA_Expr(OP, ">=", $1, $3), - makeA_Expr(OP, "<=", $1, $5)); + $$ = (Node *) makeA_Expr(AND, NIL, + (Node *) makeSimpleA_Expr(OP, ">=", $1, $3), + (Node *) makeSimpleA_Expr(OP, "<=", $1, $5)); } | a_expr NOT BETWEEN b_expr AND b_expr %prec BETWEEN { - $$ = makeA_Expr(OR, NULL, - makeA_Expr(OP, "<", $1, $4), - makeA_Expr(OP, ">", $1, $6)); + $$ = (Node *) makeA_Expr(OR, NIL, + (Node *) makeSimpleA_Expr(OP, "<", $1, $4), + (Node *) makeSimpleA_Expr(OP, ">", $1, $6)); } | a_expr IN in_expr { @@ -4932,7 +4953,8 @@ a_expr: c_expr { SubLink *n = (SubLink *)$3; n->lefthand = makeList1($1); - n->oper = (List *) makeA_Expr(OP, "=", NULL, NULL); + n->oper = (List *) makeSimpleA_Expr(OP, "=", + NULL, NULL); n->useor = FALSE; n->subLinkType = ANY_SUBLINK; $$ = (Node *)n; @@ -4943,11 +4965,13 @@ a_expr: c_expr List *l; foreach(l, (List *) $3) { - Node *cmp = makeA_Expr(OP, "=", $1, lfirst(l)); + Node *cmp; + cmp = (Node *) makeSimpleA_Expr(OP, "=", + $1, lfirst(l)); if (n == NULL) n = cmp; else - n = makeA_Expr(OR, NULL, n, cmp); + n = (Node *) makeA_Expr(OR, NIL, n, cmp); } $$ = n; } @@ -4959,7 +4983,8 @@ a_expr: c_expr { SubLink *n = (SubLink *)$4; n->lefthand = makeList1($1); - n->oper = (List *) makeA_Expr(OP, "<>", NULL, NULL); + n->oper = (List *) makeSimpleA_Expr(OP, "<>", + NULL, NULL); n->useor = FALSE; n->subLinkType = ALL_SUBLINK; $$ = (Node *)n; @@ -4970,16 +4995,18 @@ a_expr: c_expr List *l; foreach(l, (List *) $4) { - Node *cmp = makeA_Expr(OP, "<>", $1, lfirst(l)); + Node *cmp; + cmp = (Node *) makeSimpleA_Expr(OP, "<>", + $1, lfirst(l)); if (n == NULL) n = cmp; else - n = makeA_Expr(AND, NULL, n, cmp); + n = (Node *) makeA_Expr(AND, NIL, n, cmp); } $$ = n; } } - | a_expr all_Op sub_type select_with_parens %prec Op + | a_expr qual_all_Op sub_type select_with_parens %prec Op { SubLink *n = makeNode(SubLink); n->lefthand = makeList1($1); @@ -5007,42 +5034,42 @@ b_expr: c_expr | b_expr TYPECAST Typename { $$ = makeTypeCast($1, $3); } | '+' b_expr %prec UMINUS - { $$ = makeA_Expr(OP, "+", NULL, $2); } + { $$ = (Node *) makeSimpleA_Expr(OP, "+", NULL, $2); } | '-' b_expr %prec UMINUS { $$ = doNegate($2); } | '%' b_expr - { $$ = makeA_Expr(OP, "%", NULL, $2); } + { $$ = (Node *) makeSimpleA_Expr(OP, "%", NULL, $2); } | '^' b_expr - { $$ = makeA_Expr(OP, "^", NULL, $2); } + { $$ = (Node *) makeSimpleA_Expr(OP, "^", NULL, $2); } | b_expr '%' - { $$ = makeA_Expr(OP, "%", $1, NULL); } + { $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, NULL); } | b_expr '^' - { $$ = makeA_Expr(OP, "^", $1, NULL); } + { $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, NULL); } | b_expr '+' b_expr - { $$ = makeA_Expr(OP, "+", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "+", $1, $3); } | b_expr '-' b_expr - { $$ = makeA_Expr(OP, "-", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "-", $1, $3); } | b_expr '*' b_expr - { $$ = makeA_Expr(OP, "*", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "*", $1, $3); } | b_expr '/' b_expr - { $$ = makeA_Expr(OP, "/", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "/", $1, $3); } | b_expr '%' b_expr - { $$ = makeA_Expr(OP, "%", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, $3); } | b_expr '^' b_expr - { $$ = makeA_Expr(OP, "^", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, $3); } | b_expr '<' b_expr - { $$ = makeA_Expr(OP, "<", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "<", $1, $3); } | b_expr '>' b_expr - { $$ = makeA_Expr(OP, ">", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, ">", $1, $3); } | b_expr '=' b_expr - { $$ = makeA_Expr(OP, "=", $1, $3); } + { $$ = (Node *) makeSimpleA_Expr(OP, "=", $1, $3); } - | b_expr Op b_expr - { $$ = makeA_Expr(OP, $2, $1, $3); } - | Op b_expr - { $$ = makeA_Expr(OP, $1, NULL, $2); } - | b_expr Op %prec POSTFIXOP - { $$ = makeA_Expr(OP, $2, $1, NULL); } + | b_expr qual_Op b_expr %prec Op + { $$ = (Node *) makeA_Expr(OP, $2, $1, $3); } + | qual_Op b_expr %prec Op + { $$ = (Node *) makeA_Expr(OP, $1, NULL, $2); } + | b_expr qual_Op %prec POSTFIXOP + { $$ = (Node *) makeA_Expr(OP, $2, $1, NULL); } ; /* @@ -5539,12 +5566,9 @@ case_expr: CASE case_arg when_clause_list case_default END_TRANS { CaseExpr *c = makeNode(CaseExpr); CaseWhen *w = makeNode(CaseWhen); -/* - A_Const *n = makeNode(A_Const); - n->val.type = T_Null; - w->result = (Node *)n; -*/ - w->expr = makeA_Expr(OP, "=", $3, $5); + + w->expr = (Node *) makeSimpleA_Expr(OP, "=", $3, $5); + /* w->result is left NULL */ c->args = makeList1(w); c->defresult = $3; $$ = (Node *)c; @@ -6244,17 +6268,6 @@ SpecialRuleRelation: OLD %% static Node * -makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr) -{ - A_Expr *a = makeNode(A_Expr); - a->oper = oper; - a->opname = opname; - a->lexpr = lexpr; - a->rexpr = rexpr; - return (Node *)a; -} - -static Node * makeTypeCast(Node *arg, TypeName *typename) { /* @@ -6308,41 +6321,49 @@ makeFloatConst(char *str) * - thomas 1997-12-22 */ static Node * -makeRowExpr(char *opr, List *largs, List *rargs) +makeRowExpr(List *opr, List *largs, List *rargs) { Node *expr = NULL; Node *larg, *rarg; + char *oprname; if (length(largs) != length(rargs)) - elog(ERROR,"Unequal number of entries in row expression"); + elog(ERROR, "Unequal number of entries in row expression"); if (lnext(largs) != NIL) - expr = makeRowExpr(opr,lnext(largs),lnext(rargs)); + expr = makeRowExpr(opr, lnext(largs), lnext(rargs)); larg = lfirst(largs); rarg = lfirst(rargs); - if ((strcmp(opr, "=") == 0) - || (strcmp(opr, "<") == 0) - || (strcmp(opr, "<=") == 0) - || (strcmp(opr, ">") == 0) - || (strcmp(opr, ">=") == 0)) + oprname = strVal(llast(opr)); + + if ((strcmp(oprname, "=") == 0) || + (strcmp(oprname, "<") == 0) || + (strcmp(oprname, "<=") == 0) || + (strcmp(oprname, ">") == 0) || + (strcmp(oprname, ">=") == 0)) { if (expr == NULL) - expr = makeA_Expr(OP, opr, larg, rarg); + expr = (Node *) makeA_Expr(OP, opr, larg, rarg); else - expr = makeA_Expr(AND, NULL, expr, makeA_Expr(OP, opr, larg, rarg)); + expr = (Node *) makeA_Expr(AND, NIL, expr, + (Node *) makeA_Expr(OP, opr, + larg, rarg)); } - else if (strcmp(opr, "<>") == 0) + else if (strcmp(oprname, "<>") == 0) { if (expr == NULL) - expr = makeA_Expr(OP, opr, larg, rarg); + expr = (Node *) makeA_Expr(OP, opr, larg, rarg); else - expr = makeA_Expr(OR, NULL, expr, makeA_Expr(OP, opr, larg, rarg)); + expr = (Node *) makeA_Expr(OR, NIL, expr, + (Node *) makeA_Expr(OP, opr, + larg, rarg)); } else { - elog(ERROR,"Operator '%s' not implemented for row expressions",opr); + elog(ERROR, "Operator '%s' not implemented for row expressions", + oprname); } return expr; @@ -6557,7 +6578,7 @@ doNegate(Node *n) } } - return makeA_Expr(OP, "-", NULL, n); + return (Node *) makeSimpleA_Expr(OP, "-", NULL, n); } static void diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 4177e7887e..452f66284d 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.88 2002/04/15 06:05:49 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.89 2002/04/16 23:08:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -54,7 +54,7 @@ static Node *transformFromClauseItem(ParseState *pstate, Node *n, static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause); static List *addTargetToSortList(TargetEntry *tle, List *sortlist, - List *targetlist, char *opname); + List *targetlist, List *opname); static bool exprIsInSortList(Node *expr, List *sortList, List *targetList); @@ -257,22 +257,15 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars) Node *rvar = (Node *) lfirst(rvars); A_Expr *e; - e = makeNode(A_Expr); - e->oper = OP; - e->opname = "="; - e->lexpr = copyObject(lvar); - e->rexpr = copyObject(rvar); + e = makeSimpleA_Expr(OP, "=", copyObject(lvar), copyObject(rvar)); if (result == NULL) result = (Node *) e; else { - A_Expr *a = makeNode(A_Expr); + A_Expr *a; - a->oper = AND; - a->opname = NULL; - a->lexpr = result; - a->rexpr = (Node *) e; + a = makeA_Expr(AND, NIL, result, (Node *) e); result = (Node *) a; } @@ -1117,7 +1110,7 @@ transformDistinctClause(ParseState *pstate, List *distinctlist, else { *sortClause = addTargetToSortList(tle, *sortClause, - targetlist, NULL); + targetlist, NIL); /* * Probably, the tle should always have been added at the @@ -1160,7 +1153,7 @@ addAllTargetsToSortList(List *sortlist, List *targetlist) TargetEntry *tle = (TargetEntry *) lfirst(i); if (!tle->resdom->resjunk) - sortlist = addTargetToSortList(tle, sortlist, targetlist, NULL); + sortlist = addTargetToSortList(tle, sortlist, targetlist, NIL); } return sortlist; } @@ -1169,13 +1162,13 @@ addAllTargetsToSortList(List *sortlist, List *targetlist) * addTargetToSortList * If the given targetlist entry isn't already in the ORDER BY list, * add it to the end of the list, using the sortop with given name - * or any available sort operator if opname == NULL. + * or any available sort operator if opname == NIL. * * Returns the updated ORDER BY list. */ static List * addTargetToSortList(TargetEntry *tle, List *sortlist, List *targetlist, - char *opname) + List *opname) { /* avoid making duplicate sortlist entries */ if (!exprIsInSortList(tle->expr, sortlist, targetlist)) diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 916c1da4a6..a352548748 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.114 2002/04/11 20:00:00 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.115 2002/04/16 23:08:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -192,7 +192,8 @@ transformExpr(ParseState *pstate, Node *expr) * into IS NULL exprs. */ if (Transform_null_equals && - strcmp(a->opname, "=") == 0 && + length(a->name) == 1 && + strcmp(strVal(lfirst(a->name)), "=") == 0 && (exprIsNullConstant(a->lexpr) || exprIsNullConstant(a->rexpr))) { @@ -215,7 +216,7 @@ transformExpr(ParseState *pstate, Node *expr) Node *rexpr = transformExpr(pstate, a->rexpr); - result = (Node *) make_op(a->opname, + result = (Node *) make_op(a->name, lexpr, rexpr); } @@ -366,21 +367,23 @@ transformExpr(ParseState *pstate, Node *expr) /* ALL, ANY, or MULTIEXPR: generate operator list */ List *left_list = sublink->lefthand; List *right_list = qtree->targetList; - char *op; + List *op; + char *opname; List *elist; foreach(elist, left_list) lfirst(elist) = transformExpr(pstate, lfirst(elist)); Assert(IsA(sublink->oper, A_Expr)); - op = ((A_Expr *) sublink->oper)->opname; + op = ((A_Expr *) sublink->oper)->name; + opname = strVal(llast(op)); sublink->oper = NIL; /* Combining operators other than =/<> is dubious... */ if (length(left_list) != 1 && - strcmp(op, "=") != 0 && strcmp(op, "<>") != 0) + strcmp(opname, "=") != 0 && strcmp(opname, "<>") != 0) elog(ERROR, "Row comparison cannot use '%s'", - op); + opname); /* * Scan subquery's targetlist to find values that will @@ -420,7 +423,7 @@ transformExpr(ParseState *pstate, Node *expr) if (opform->oprresult != BOOLOID) elog(ERROR, "'%s' result type of '%s' must return '%s'" " to be used with quantified predicate subquery", - op, typeidTypeName(opform->oprresult), + opname, typeidTypeName(opform->oprresult), typeidTypeName(BOOLOID)); newop = makeOper(oprid(optup), /* opno */ @@ -459,13 +462,8 @@ transformExpr(ParseState *pstate, Node *expr) if (c->arg != NULL) { /* shorthand form was specified, so expand... */ - A_Expr *a = makeNode(A_Expr); - - a->oper = OP; - a->opname = "="; - a->lexpr = c->arg; - a->rexpr = warg; - warg = (Node *) a; + warg = (Node *) makeSimpleA_Expr(OP, "=", + c->arg, warg); } neww->expr = transformExpr(pstate, warg); diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 0868f3f0bb..8a3dc4d557 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.61 2002/04/11 20:00:01 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.62 2002/04/16 23:08:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -62,10 +62,7 @@ make_parsestate(ParseState *parentParseState) * Ensure argument type match by forcing conversion of constants. */ Node * -make_operand(char *opname, - Node *tree, - Oid orig_typeId, - Oid target_typeId) +make_operand(Node *tree, Oid orig_typeId, Oid target_typeId) { Node *result; @@ -95,7 +92,7 @@ make_operand(char *opname, * This is where some type conversion happens. */ Expr * -make_op(char *opname, Node *ltree, Node *rtree) +make_op(List *opname, Node *ltree, Node *rtree) { Oid ltypeId, rtypeId; @@ -114,7 +111,7 @@ make_op(char *opname, Node *ltree, Node *rtree) { tup = right_oper(opname, ltypeId); opform = (Form_pg_operator) GETSTRUCT(tup); - left = make_operand(opname, ltree, ltypeId, opform->oprleft); + left = make_operand(ltree, ltypeId, opform->oprleft); right = NULL; } @@ -123,7 +120,7 @@ make_op(char *opname, Node *ltree, Node *rtree) { tup = left_oper(opname, rtypeId); opform = (Form_pg_operator) GETSTRUCT(tup); - right = make_operand(opname, rtree, rtypeId, opform->oprright); + right = make_operand(rtree, rtypeId, opform->oprright); left = NULL; } @@ -132,8 +129,8 @@ make_op(char *opname, Node *ltree, Node *rtree) { tup = oper(opname, ltypeId, rtypeId, false); opform = (Form_pg_operator) GETSTRUCT(tup); - left = make_operand(opname, ltree, ltypeId, opform->oprleft); - right = make_operand(opname, rtree, rtypeId, opform->oprright); + left = make_operand(ltree, ltypeId, opform->oprleft); + right = make_operand(rtree, rtypeId, opform->oprright); } newop = makeOper(oprid(tup), /* opno */ diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index 028bfab431..52ae39cccd 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.54 2002/04/11 20:00:02 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.55 2002/04/16 23:08:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,7 @@ #include "access/heapam.h" #include "catalog/catname.h" #include "catalog/indexing.h" +#include "catalog/namespace.h" #include "catalog/pg_operator.h" #include "parser/parse_coerce.h" #include "parser/parse_func.h" @@ -28,17 +29,106 @@ #include "utils/fmgroids.h" #include "utils/syscache.h" -static Oid *oper_select_candidate(int nargs, Oid *input_typeids, - CandidateList candidates); -static Operator oper_exact(char *op, Oid arg1, Oid arg2); -static Operator oper_inexact(char *op, Oid arg1, Oid arg2); -static int binary_oper_get_candidates(char *opname, - CandidateList *candidates); -static int unary_oper_get_candidates(char *opname, - CandidateList *candidates, - char rightleft); -static void op_error(char *op, Oid arg1, Oid arg2); -static void unary_op_error(char *op, Oid arg, bool is_left_op); +static Oid binary_oper_exact(Oid arg1, Oid arg2, + FuncCandidateList candidates); +static Oid oper_select_candidate(int nargs, Oid *input_typeids, + FuncCandidateList candidates); +static void op_error(List *op, Oid arg1, Oid arg2); +static void unary_op_error(List *op, Oid arg, bool is_left_op); + + +/* + * LookupOperName + * Given a possibly-qualified operator name and exact input datatypes, + * look up the operator. Returns InvalidOid if no such operator. + * + * 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 +LookupOperName(List *opername, Oid oprleft, Oid oprright) +{ + FuncCandidateList clist; + char oprkind; + + if (!OidIsValid(oprleft)) + oprkind = 'l'; + else if (!OidIsValid(oprright)) + oprkind = 'r'; + else + oprkind = 'b'; + + clist = OpernameGetCandidates(opername, oprkind); + + while (clist) + { + if (clist->args[0] == oprleft && clist->args[1] == oprright) + return clist->oid; + clist = clist->next; + } + + return InvalidOid; +} + +/* + * LookupOperNameTypeNames + * Like LookupOperName, but the argument types are specified by + * TypeName nodes. Also, if we fail to find the operator + * and caller is not NULL, then an error is reported. + * + * Pass oprleft = NULL for a prefix op, oprright = NULL for a postfix op. + */ +Oid +LookupOperNameTypeNames(List *opername, TypeName *oprleft, + TypeName *oprright, const char *caller) +{ + Oid operoid; + Oid leftoid, + rightoid; + + if (oprleft == NULL) + leftoid = InvalidOid; + else + { + leftoid = LookupTypeName(oprleft); + if (!OidIsValid(leftoid)) + elog(ERROR, "Type \"%s\" does not exist", + TypeNameToString(oprleft)); + } + if (oprright == NULL) + rightoid = InvalidOid; + else + { + rightoid = LookupTypeName(oprright); + if (!OidIsValid(rightoid)) + elog(ERROR, "Type \"%s\" does not exist", + TypeNameToString(oprright)); + } + + operoid = LookupOperName(opername, leftoid, rightoid); + + if (!OidIsValid(operoid) && caller != NULL) + { + if (oprleft == NULL) + elog(ERROR, "%s: Prefix operator '%s' for type '%s' does not exist", + caller, NameListToString(opername), + TypeNameToString(oprright)); + else if (oprright == NULL) + elog(ERROR, "%s: Postfix operator '%s' for type '%s' does not exist", + caller, NameListToString(opername), + TypeNameToString(oprleft)); + else + elog(ERROR, "%s: Operator '%s' for types '%s' and '%s' does not exist", + caller, NameListToString(opername), + TypeNameToString(oprleft), + TypeNameToString(oprright)); + } + + return operoid; +} /* Select an ordering operator for the given datatype */ @@ -47,7 +137,8 @@ any_ordering_op(Oid argtype) { Oid order_opid; - order_opid = compatible_oper_opid("<", argtype, argtype, true); + order_opid = compatible_oper_opid(makeList1(makeString("<")), + argtype, argtype, true); if (!OidIsValid(order_opid)) elog(ERROR, "Unable to identify an ordering operator '%s' for type '%s'" "\n\tUse an explicit ordering operator or modify the query", @@ -72,116 +163,32 @@ oprfuncid(Operator op) } -/* binary_oper_get_candidates() - * given opname, find all possible input type pairs for which an operator - * named opname exists. - * Build a list of the candidate input types. - * Returns number of candidates found. +/* binary_oper_exact() + * Check for an "exact" match to the specified operand types. + * + * If one operand is an unknown literal, assume it should be taken to be + * the same type as the other operand for this purpose. */ -static int -binary_oper_get_candidates(char *opname, - CandidateList *candidates) +static Oid +binary_oper_exact(Oid arg1, Oid arg2, + FuncCandidateList candidates) { - Relation pg_operator_desc; - SysScanDesc pg_operator_scan; - HeapTuple tup; - int ncandidates = 0; - ScanKeyData opKey[1]; - - *candidates = NULL; - - ScanKeyEntryInitialize(&opKey[0], 0, - Anum_pg_operator_oprname, - F_NAMEEQ, - NameGetDatum(opname)); - - pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock); - pg_operator_scan = systable_beginscan(pg_operator_desc, - OperatorNameIndex, true, - SnapshotNow, - 1, opKey); - - while (HeapTupleIsValid(tup = systable_getnext(pg_operator_scan))) - { - Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tup); - - if (oper->oprkind == 'b') - { - CandidateList current_candidate; - - current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList)); - current_candidate->args = (Oid *) palloc(2 * sizeof(Oid)); - - current_candidate->args[0] = oper->oprleft; - current_candidate->args[1] = oper->oprright; - current_candidate->next = *candidates; - *candidates = current_candidate; - ncandidates++; - } - } - - systable_endscan(pg_operator_scan); - heap_close(pg_operator_desc, AccessShareLock); - - return ncandidates; -} /* binary_oper_get_candidates() */ + /* Unspecified type for one of the arguments? then use the other */ + if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid)) + arg1 = arg2; + else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid)) + arg2 = arg1; -/* unary_oper_get_candidates() - * given opname, find all possible types for which - * a right/left unary operator named opname exists. - * Build a list of the candidate input types. - * Returns number of candidates found. - */ -static int -unary_oper_get_candidates(char *opname, - CandidateList *candidates, - char rightleft) -{ - Relation pg_operator_desc; - SysScanDesc pg_operator_scan; - HeapTuple tup; - int ncandidates = 0; - ScanKeyData opKey[1]; - - *candidates = NULL; - - ScanKeyEntryInitialize(&opKey[0], 0, - Anum_pg_operator_oprname, - F_NAMEEQ, - NameGetDatum(opname)); - - pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock); - pg_operator_scan = systable_beginscan(pg_operator_desc, - OperatorNameIndex, true, - SnapshotNow, - 1, opKey); - - while (HeapTupleIsValid(tup = systable_getnext(pg_operator_scan))) + while (candidates != NULL) { - Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tup); - - if (oper->oprkind == rightleft) - { - CandidateList current_candidate; - - current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList)); - current_candidate->args = (Oid *) palloc(sizeof(Oid)); - - if (rightleft == 'r') - current_candidate->args[0] = oper->oprleft; - else - current_candidate->args[0] = oper->oprright; - current_candidate->next = *candidates; - *candidates = current_candidate; - ncandidates++; - } + if (arg1 == candidates->args[0] && + arg2 == candidates->args[1]) + return candidates->oid; + candidates = candidates->next; } - systable_endscan(pg_operator_scan); - heap_close(pg_operator_desc, AccessShareLock); - - return ncandidates; -} /* unary_oper_get_candidates() */ + return InvalidOid; +} /* oper_select_candidate() @@ -234,13 +241,13 @@ unary_oper_get_candidates(char *opname, * some sense. (see equivalentOpersAfterPromotion for details.) * - ay 6/95 */ -static Oid * +static Oid oper_select_candidate(int nargs, Oid *input_typeids, - CandidateList candidates) + FuncCandidateList candidates) { - CandidateList current_candidate; - CandidateList last_candidate; + FuncCandidateList current_candidate; + FuncCandidateList last_candidate; Oid *current_typeids; Oid current_type; int unknownOids; @@ -289,9 +296,9 @@ oper_select_candidate(int nargs, /* Done if no candidate or only one candidate survives */ if (ncandidates == 0) - return NULL; + return InvalidOid; if (ncandidates == 1) - return candidates->args; + return candidates->oid; /* * Run through all candidates and keep those with the most matches on @@ -335,7 +342,7 @@ oper_select_candidate(int nargs, last_candidate->next = NULL; if (ncandidates == 1) - return candidates->args; + return candidates->oid; /* * Still too many candidates? Run through all candidates and keep @@ -382,7 +389,7 @@ oper_select_candidate(int nargs, last_candidate->next = NULL; if (ncandidates == 1) - return candidates->args; + return candidates->oid; /* * Still too many candidates? Now look for candidates which are @@ -428,7 +435,7 @@ oper_select_candidate(int nargs, last_candidate->next = NULL; if (ncandidates == 1) - return candidates->args; + return candidates->oid; /* * Still too many candidates? Try assigning types for the unknown @@ -467,7 +474,7 @@ oper_select_candidate(int nargs, nmatch++; } if (nmatch == nargs) - return current_typeids; + return current_candidate->oid; } } @@ -602,87 +609,12 @@ oper_select_candidate(int nargs, } if (ncandidates == 1) - return candidates->args; + return candidates->oid; - return NULL; /* failed to determine a unique candidate */ + return InvalidOid; /* failed to determine a unique candidate */ } /* oper_select_candidate() */ -/* oper_exact() - * Given operator, types of arg1 and arg2, return oper struct or NULL. - * - * NOTE: on success, the returned object is a syscache entry. The caller - * must ReleaseSysCache() the entry when done with it. - */ -static Operator -oper_exact(char *op, Oid arg1, Oid arg2) -{ - HeapTuple tup; - - /* Unspecified type for one of the arguments? then use the other */ - if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid)) - arg1 = arg2; - else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid)) - arg2 = arg1; - - tup = SearchSysCache(OPERNAME, - PointerGetDatum(op), - ObjectIdGetDatum(arg1), - ObjectIdGetDatum(arg2), - CharGetDatum('b')); - - return (Operator) tup; -} - - -/* oper_inexact() - * Given operator, types of arg1 and arg2, return oper struct or NULL. - * - * NOTE: on success, the returned object is a syscache entry. The caller - * must ReleaseSysCache() the entry when done with it. - */ -static Operator -oper_inexact(char *op, Oid arg1, Oid arg2) -{ - HeapTuple tup; - CandidateList candidates; - int ncandidates; - Oid *targetOids; - Oid inputOids[2]; - - /* Unspecified type for one of the arguments? then use the other */ - if (arg2 == InvalidOid) - arg2 = arg1; - if (arg1 == InvalidOid) - arg1 = arg2; - - ncandidates = binary_oper_get_candidates(op, &candidates); - - /* No operators found? Then return null... */ - if (ncandidates == 0) - return NULL; - - /* - * Otherwise, check for compatible datatypes, and then try to resolve - * the conflict if more than one candidate remains. - */ - inputOids[0] = arg1; - inputOids[1] = arg2; - targetOids = oper_select_candidate(2, inputOids, candidates); - if (targetOids != NULL) - { - tup = SearchSysCache(OPERNAME, - PointerGetDatum(op), - ObjectIdGetDatum(targetOids[0]), - ObjectIdGetDatum(targetOids[1]), - CharGetDatum('b')); - } - else - tup = NULL; - return (Operator) tup; -} - - /* oper() -- search for a binary operator * Given operator name, types of arg1 and arg2, return oper struct. * @@ -697,22 +629,48 @@ oper_inexact(char *op, Oid arg1, Oid arg2) * must ReleaseSysCache() the entry when done with it. */ Operator -oper(char *opname, Oid ltypeId, Oid rtypeId, bool noError) +oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError) { - HeapTuple tup; + FuncCandidateList clist; + Oid operOid; + Oid inputOids[2]; + HeapTuple tup = NULL; - /* check for exact match on this operator... */ - if (HeapTupleIsValid(tup = oper_exact(opname, ltypeId, rtypeId))) - return (Operator) tup; + /* Get binary operators of given name */ + clist = OpernameGetCandidates(opname, 'b'); - /* try to find a match on likely candidates... */ - if (HeapTupleIsValid(tup = oper_inexact(opname, ltypeId, rtypeId))) - return (Operator) tup; + /* No operators found? Then fail... */ + if (clist != NULL) + { + /* + * Check for an "exact" match. + */ + operOid = binary_oper_exact(ltypeId, rtypeId, clist); + if (!OidIsValid(operOid)) + { + /* + * Otherwise, search for the most suitable candidate. + */ - if (!noError) + /* Unspecified type for one of the arguments? then use the other */ + if (rtypeId == InvalidOid) + rtypeId = ltypeId; + else if (ltypeId == InvalidOid) + ltypeId = rtypeId; + inputOids[0] = ltypeId; + inputOids[1] = rtypeId; + operOid = oper_select_candidate(2, inputOids, clist); + } + if (OidIsValid(operOid)) + tup = SearchSysCache(OPEROID, + ObjectIdGetDatum(operOid), + 0, 0, 0); + } + + if (!HeapTupleIsValid(tup) && !noError) op_error(opname, ltypeId, rtypeId); - return (Operator) NULL; + return (Operator) tup; } /* compatible_oper() @@ -723,7 +681,7 @@ oper(char *opname, Oid ltypeId, Oid rtypeId, bool noError) * are accepted). Otherwise, the semantics are the same. */ Operator -compatible_oper(char *op, Oid arg1, Oid arg2, bool noError) +compatible_oper(List *op, Oid arg1, Oid arg2, bool noError) { Operator optup; Form_pg_operator opform; @@ -755,7 +713,7 @@ compatible_oper(char *op, Oid arg1, Oid arg2, bool noError) * lookup fails and noError is true. */ Oid -compatible_oper_opid(char *op, Oid arg1, Oid arg2, bool noError) +compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError) { Operator optup; Oid result; @@ -777,7 +735,7 @@ compatible_oper_opid(char *op, Oid arg1, Oid arg2, bool noError) * lookup fails and noError is true. */ Oid -compatible_oper_funcid(char *op, Oid arg1, Oid arg2, bool noError) +compatible_oper_funcid(List *op, Oid arg1, Oid arg2, bool noError) { Operator optup; Oid result; @@ -805,46 +763,50 @@ compatible_oper_funcid(char *op, Oid arg1, Oid arg2, bool noError) * must ReleaseSysCache() the entry when done with it. */ Operator -right_oper(char *op, Oid arg) +right_oper(List *op, Oid arg) { - HeapTuple tup; - CandidateList candidates; - int ncandidates; - Oid *targetOid; + FuncCandidateList clist; + Oid operOid = InvalidOid; + HeapTuple tup = NULL; - /* Try for exact match */ - tup = SearchSysCache(OPERNAME, - PointerGetDatum(op), - ObjectIdGetDatum(arg), - ObjectIdGetDatum(InvalidOid), - CharGetDatum('r')); + /* Find candidates */ + clist = OpernameGetCandidates(op, 'r'); - if (!HeapTupleIsValid(tup)) + if (clist != NULL) { - /* Try for inexact matches */ - ncandidates = unary_oper_get_candidates(op, &candidates, 'r'); - if (ncandidates == 0) - unary_op_error(op, arg, FALSE); - else + /* + * First, quickly check to see if there is an exactly matching + * operator (there can be only one such entry in the list). + */ + FuncCandidateList clisti; + + for (clisti = clist; clisti != NULL; clisti = clisti->next) + { + if (arg == clisti->args[0]) + { + operOid = clisti->oid; + break; + } + } + + if (!OidIsValid(operOid)) { /* * We must run oper_select_candidate even if only one * candidate, otherwise we may falsely return a * non-type-compatible operator. */ - targetOid = oper_select_candidate(1, &arg, candidates); - if (targetOid != NULL) - tup = SearchSysCache(OPERNAME, - PointerGetDatum(op), - ObjectIdGetDatum(targetOid[0]), - ObjectIdGetDatum(InvalidOid), - CharGetDatum('r')); + operOid = oper_select_candidate(1, &arg, clist); } - - if (!HeapTupleIsValid(tup)) - unary_op_error(op, arg, FALSE); + if (OidIsValid(operOid)) + tup = SearchSysCache(OPEROID, + ObjectIdGetDatum(operOid), + 0, 0, 0); } + if (!HeapTupleIsValid(tup)) + unary_op_error(op, arg, FALSE); + return (Operator) tup; } /* right_oper() */ @@ -861,46 +823,55 @@ right_oper(char *op, Oid arg) * must ReleaseSysCache() the entry when done with it. */ Operator -left_oper(char *op, Oid arg) +left_oper(List *op, Oid arg) { - HeapTuple tup; - CandidateList candidates; - int ncandidates; - Oid *targetOid; + FuncCandidateList clist; + Oid operOid = InvalidOid; + HeapTuple tup = NULL; - /* Try for exact match */ - tup = SearchSysCache(OPERNAME, - PointerGetDatum(op), - ObjectIdGetDatum(InvalidOid), - ObjectIdGetDatum(arg), - CharGetDatum('l')); + /* Find candidates */ + clist = OpernameGetCandidates(op, 'l'); - if (!HeapTupleIsValid(tup)) + if (clist != NULL) { - /* Try for inexact matches */ - ncandidates = unary_oper_get_candidates(op, &candidates, 'l'); - if (ncandidates == 0) - unary_op_error(op, arg, TRUE); - else + /* + * 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! + */ + FuncCandidateList clisti; + + for (clisti = clist; clisti != NULL; clisti = clisti->next) + { + clisti->args[0] = clisti->args[1]; + if (arg == clisti->args[0]) + { + operOid = clisti->oid; + break; + } + } + + if (!OidIsValid(operOid)) { /* * We must run oper_select_candidate even if only one * candidate, otherwise we may falsely return a * non-type-compatible operator. */ - targetOid = oper_select_candidate(1, &arg, candidates); - if (targetOid != NULL) - tup = SearchSysCache(OPERNAME, - PointerGetDatum(op), - ObjectIdGetDatum(InvalidOid), - ObjectIdGetDatum(targetOid[0]), - CharGetDatum('l')); + operOid = oper_select_candidate(1, &arg, clist); } - - if (!HeapTupleIsValid(tup)) - unary_op_error(op, arg, TRUE); + if (OidIsValid(operOid)) + tup = SearchSysCache(OPEROID, + ObjectIdGetDatum(operOid), + 0, 0, 0); } + if (!HeapTupleIsValid(tup)) + unary_op_error(op, arg, TRUE); + return (Operator) tup; } /* left_oper() */ @@ -910,19 +881,22 @@ left_oper(char *op, Oid arg) * is not found. */ static void -op_error(char *op, Oid arg1, Oid arg2) +op_error(List *op, Oid arg1, Oid arg2) { if (!typeidIsValid(arg1)) elog(ERROR, "Left hand side of operator '%s' has an unknown type" - "\n\tProbably a bad attribute name", op); + "\n\tProbably a bad attribute name", + NameListToString(op)); if (!typeidIsValid(arg2)) elog(ERROR, "Right hand side of operator %s has an unknown type" - "\n\tProbably a bad attribute name", op); + "\n\tProbably a bad attribute name", + NameListToString(op)); elog(ERROR, "Unable to identify an operator '%s' for types '%s' and '%s'" "\n\tYou will have to retype this query using an explicit cast", - op, format_type_be(arg1), format_type_be(arg2)); + NameListToString(op), + format_type_be(arg1), format_type_be(arg2)); } /* unary_op_error() @@ -930,28 +904,28 @@ op_error(char *op, Oid arg1, Oid arg2) * is not found. */ static void -unary_op_error(char *op, Oid arg, bool is_left_op) +unary_op_error(List *op, Oid arg, bool is_left_op) { if (!typeidIsValid(arg)) { if (is_left_op) elog(ERROR, "operand of prefix operator '%s' has an unknown type" "\n\t(probably an invalid column reference)", - op); + NameListToString(op)); else elog(ERROR, "operand of postfix operator '%s' has an unknown type" "\n\t(probably an invalid column reference)", - op); + NameListToString(op)); } else { if (is_left_op) elog(ERROR, "Unable to identify a prefix operator '%s' for type '%s'" "\n\tYou may need to add parentheses or an explicit cast", - op, format_type_be(arg)); + NameListToString(op), format_type_be(arg)); else elog(ERROR, "Unable to identify a postfix operator '%s' for type '%s'" "\n\tYou may need to add parentheses or an explicit cast", - op, format_type_be(arg)); + NameListToString(op), format_type_be(arg)); } } diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index f9accfefc2..e0b465ec98 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -18,7 +18,7 @@ * Portions Copyright (c) 2000-2001, PostgreSQL Global Development Group * Copyright 1999 Jan Wieck * - * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.36 2002/04/02 01:03:07 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.37 2002/04/16 23:08:11 tgl Exp $ * * ---------- */ @@ -36,6 +36,7 @@ #include "catalog/pg_operator.h" #include "commands/trigger.h" #include "executor/spi_priv.h" +#include "parser/parse_oper.h" #include "utils/lsyscache.h" #include "miscadmin.h" @@ -3338,27 +3339,20 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue) HASH_FIND, NULL); /* - * If not found, lookup the OPERNAME system cache for it to get the - * func OID, then do the function manager lookup, and remember that - * info. + * If not found, lookup the operator, then do the function manager + * lookup, and remember that info. */ if (!entry) { - HeapTuple opr_tup; Oid opr_proc; FmgrInfo finfo; - opr_tup = SearchSysCache(OPERNAME, - PointerGetDatum("="), - ObjectIdGetDatum(typeid), - ObjectIdGetDatum(typeid), - CharGetDatum('b')); - if (!HeapTupleIsValid(opr_tup)) + opr_proc = compatible_oper_funcid(makeList1(makeString("=")), + typeid, typeid, true); + if (!OidIsValid(opr_proc)) elog(ERROR, - "ri_AttributesEqual(): cannot find '=' operator for type %u", + "ri_AttributesEqual(): cannot find '=' operator for type %u", typeid); - opr_proc = ((Form_pg_operator) GETSTRUCT(opr_tup))->oprcode; - ReleaseSysCache(opr_tup); /* * Since fmgr_info could fail, call it *before* creating the diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index e8e71dec25..3b1af8df5e 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.107 2002/04/03 05:39:31 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.108 2002/04/16 23:08:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -74,6 +74,7 @@ #include "access/heapam.h" #include "catalog/catname.h" +#include "catalog/pg_namespace.h" #include "catalog/pg_operator.h" #include "catalog/pg_proc.h" #include "catalog/pg_statistic.h" @@ -3285,14 +3286,15 @@ string_lessthan(const char *str1, const char *str2, Oid datatype) } /* See if there is a binary op of the given name for the given datatype */ +/* NB: we assume that only built-in system operators are searched for */ static Oid find_operator(const char *opname, Oid datatype) { - return GetSysCacheOid(OPERNAME, + return GetSysCacheOid(OPERNAMENSP, PointerGetDatum(opname), ObjectIdGetDatum(datatype), ObjectIdGetDatum(datatype), - CharGetDatum('b')); + ObjectIdGetDatum(PG_CATALOG_NAMESPACE)); } /* diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 17ea1abdd0..6699a179d3 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.69 2002/04/05 00:31:30 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.70 2002/04/16 23:08:11 tgl Exp $ * * NOTES * Eventually, the index information should go through here, too. @@ -378,10 +378,6 @@ op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp) * ltype ">" rtype) for an operator previously determined to be * mergejoinable. Optionally, fetches the regproc ids of these * operators, as well as their operator OIDs. - * - * Raises error if operators cannot be found. Assuming that the operator - * had indeed been marked mergejoinable, this indicates that whoever marked - * it so was mistaken. */ void op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop, @@ -389,11 +385,9 @@ op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop, { HeapTuple tp; Form_pg_operator optup; - Oid oprleft, - oprright; /* - * Get the declared left and right operand types of the operator. + * Get the declared comparison operators of the operator. */ tp = SearchSysCache(OPEROID, ObjectIdGetDatum(opno), @@ -401,44 +395,23 @@ op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop, if (!HeapTupleIsValid(tp)) /* shouldn't happen */ elog(ERROR, "op_mergejoin_crossops: operator %u not found", opno); optup = (Form_pg_operator) GETSTRUCT(tp); - oprleft = optup->oprleft; - oprright = optup->oprright; + *ltop = optup->oprltcmpop; + *gtop = optup->oprgtcmpop; ReleaseSysCache(tp); - /* - * Look up the "<" operator with the same input types. If there isn't - * one, whoever marked the "=" operator mergejoinable was a loser. - */ - tp = SearchSysCache(OPERNAME, - PointerGetDatum("<"), - ObjectIdGetDatum(oprleft), - ObjectIdGetDatum(oprright), - CharGetDatum('b')); - if (!HeapTupleIsValid(tp)) + /* Check < op provided */ + if (!OidIsValid(*ltop)) elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching < operator", opno); - optup = (Form_pg_operator) GETSTRUCT(tp); - *ltop = tp->t_data->t_oid; if (ltproc) - *ltproc = optup->oprcode; - ReleaseSysCache(tp); + *ltproc = get_opcode(*ltop); - /* - * And the same for the ">" operator. - */ - tp = SearchSysCache(OPERNAME, - PointerGetDatum(">"), - ObjectIdGetDatum(oprleft), - ObjectIdGetDatum(oprright), - CharGetDatum('b')); - if (!HeapTupleIsValid(tp)) + /* Check > op provided */ + if (!OidIsValid(*gtop)) elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching > operator", opno); - optup = (Form_pg_operator) GETSTRUCT(tp); - *gtop = tp->t_data->t_oid; if (gtproc) - *gtproc = optup->oprcode; - ReleaseSysCache(tp); + *gtproc = get_opcode(*gtop); } /* diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 6808c07f4b..720d19225c 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.76 2002/04/11 20:00:06 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.77 2002/04/16 23:08:11 tgl Exp $ * * NOTES * These routines allow the parser/planner/executor to perform @@ -273,15 +273,15 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }}, - {OperatorRelationName, /* OPERNAME */ - OperatorNameIndex, + {OperatorRelationName, /* OPERNAMENSP */ + OperatorNameNspIndex, 0, 4, { Anum_pg_operator_oprname, Anum_pg_operator_oprleft, Anum_pg_operator_oprright, - Anum_pg_operator_oprkind + Anum_pg_operator_oprnamespace }}, {OperatorRelationName, /* OPEROID */ OperatorOidIndex, |
