Header And Logo

PostgreSQL
| The world's most advanced open source database.

pg_operator.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * pg_operator.c
00004  *    routines to support manipulation of the pg_operator relation
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/catalog/pg_operator.c
00012  *
00013  * NOTES
00014  *    these routines moved here from commands/define.c and somewhat cleaned up.
00015  *
00016  *-------------------------------------------------------------------------
00017  */
00018 #include "postgres.h"
00019 
00020 #include "access/heapam.h"
00021 #include "access/htup_details.h"
00022 #include "access/xact.h"
00023 #include "catalog/dependency.h"
00024 #include "catalog/indexing.h"
00025 #include "catalog/namespace.h"
00026 #include "catalog/objectaccess.h"
00027 #include "catalog/pg_namespace.h"
00028 #include "catalog/pg_operator.h"
00029 #include "catalog/pg_proc.h"
00030 #include "catalog/pg_type.h"
00031 #include "miscadmin.h"
00032 #include "parser/parse_oper.h"
00033 #include "utils/acl.h"
00034 #include "utils/builtins.h"
00035 #include "utils/lsyscache.h"
00036 #include "utils/rel.h"
00037 #include "utils/syscache.h"
00038 
00039 
00040 static Oid OperatorGet(const char *operatorName,
00041             Oid operatorNamespace,
00042             Oid leftObjectId,
00043             Oid rightObjectId,
00044             bool *defined);
00045 
00046 static Oid OperatorLookup(List *operatorName,
00047                Oid leftObjectId,
00048                Oid rightObjectId,
00049                bool *defined);
00050 
00051 static Oid OperatorShellMake(const char *operatorName,
00052                   Oid operatorNamespace,
00053                   Oid leftTypeId,
00054                   Oid rightTypeId);
00055 
00056 static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
00057 
00058 static Oid get_other_operator(List *otherOp,
00059                    Oid otherLeftTypeId, Oid otherRightTypeId,
00060                    const char *operatorName, Oid operatorNamespace,
00061                    Oid leftTypeId, Oid rightTypeId,
00062                    bool isCommutator);
00063 
00064 static void makeOperatorDependencies(HeapTuple tuple);
00065 
00066 
00067 /*
00068  * Check whether a proposed operator name is legal
00069  *
00070  * This had better match the behavior of parser/scan.l!
00071  *
00072  * We need this because the parser is not smart enough to check that
00073  * the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses
00074  * are operator names rather than some other lexical entity.
00075  */
00076 static bool
00077 validOperatorName(const char *name)
00078 {
00079     size_t      len = strlen(name);
00080 
00081     /* Can't be empty or too long */
00082     if (len == 0 || len >= NAMEDATALEN)
00083         return false;
00084 
00085     /* Can't contain any invalid characters */
00086     /* Test string here should match op_chars in scan.l */
00087     if (strspn(name, "[email protected]#^&|`?+-*/%<>=") != len)
00088         return false;
00089 
00090     /* Can't contain slash-star or dash-dash (comment starts) */
00091     if (strstr(name, "/*") || strstr(name, "--"))
00092         return false;
00093 
00094     /*
00095      * For SQL standard compatibility, '+' and '-' cannot be the last char of a
00096      * multi-char operator unless the operator contains chars that are not in
00097      * SQL operators. The idea is to lex '=-' as two operators, but not to
00098      * forbid operator names like '?-' that could not be sequences of standard SQL
00099      * operators.
00100      */
00101     if (len > 1 &&
00102         (name[len - 1] == '+' ||
00103          name[len - 1] == '-'))
00104     {
00105         int         ic;
00106 
00107         for (ic = len - 2; ic >= 0; ic--)
00108         {
00109             if (strchr("[email protected]#^&|`?%", name[ic]))
00110                 break;
00111         }
00112         if (ic < 0)
00113             return false;       /* nope, not valid */
00114     }
00115 
00116     /* != isn't valid either, because parser will convert it to <> */
00117     if (strcmp(name, "!=") == 0)
00118         return false;
00119 
00120     return true;
00121 }
00122 
00123 
00124 /*
00125  * OperatorGet
00126  *
00127  *      finds an operator given an exact specification (name, namespace,
00128  *      left and right type IDs).
00129  *
00130  *      *defined is set TRUE if defined (not a shell)
00131  */
00132 static Oid
00133 OperatorGet(const char *operatorName,
00134             Oid operatorNamespace,
00135             Oid leftObjectId,
00136             Oid rightObjectId,
00137             bool *defined)
00138 {
00139     HeapTuple   tup;
00140     Oid         operatorObjectId;
00141 
00142     tup = SearchSysCache4(OPERNAMENSP,
00143                           PointerGetDatum(operatorName),
00144                           ObjectIdGetDatum(leftObjectId),
00145                           ObjectIdGetDatum(rightObjectId),
00146                           ObjectIdGetDatum(operatorNamespace));
00147     if (HeapTupleIsValid(tup))
00148     {
00149         RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
00150 
00151         operatorObjectId = HeapTupleGetOid(tup);
00152         *defined = RegProcedureIsValid(oprcode);
00153         ReleaseSysCache(tup);
00154     }
00155     else
00156     {
00157         operatorObjectId = InvalidOid;
00158         *defined = false;
00159     }
00160 
00161     return operatorObjectId;
00162 }
00163 
00164 /*
00165  * OperatorLookup
00166  *
00167  *      looks up an operator given a possibly-qualified name and
00168  *      left and right type IDs.
00169  *
00170  *      *defined is set TRUE if defined (not a shell)
00171  */
00172 static Oid
00173 OperatorLookup(List *operatorName,
00174                Oid leftObjectId,
00175                Oid rightObjectId,
00176                bool *defined)
00177 {
00178     Oid         operatorObjectId;
00179     RegProcedure oprcode;
00180 
00181     operatorObjectId = LookupOperName(NULL, operatorName,
00182                                       leftObjectId, rightObjectId,
00183                                       true, -1);
00184     if (!OidIsValid(operatorObjectId))
00185     {
00186         *defined = false;
00187         return InvalidOid;
00188     }
00189 
00190     oprcode = get_opcode(operatorObjectId);
00191     *defined = RegProcedureIsValid(oprcode);
00192 
00193     return operatorObjectId;
00194 }
00195 
00196 
00197 /*
00198  * OperatorShellMake
00199  *      Make a "shell" entry for a not-yet-existing operator.
00200  */
00201 static Oid
00202 OperatorShellMake(const char *operatorName,
00203                   Oid operatorNamespace,
00204                   Oid leftTypeId,
00205                   Oid rightTypeId)
00206 {
00207     Relation    pg_operator_desc;
00208     Oid         operatorObjectId;
00209     int         i;
00210     HeapTuple   tup;
00211     Datum       values[Natts_pg_operator];
00212     bool        nulls[Natts_pg_operator];
00213     NameData    oname;
00214     TupleDesc   tupDesc;
00215 
00216     /*
00217      * validate operator name
00218      */
00219     if (!validOperatorName(operatorName))
00220         ereport(ERROR,
00221                 (errcode(ERRCODE_INVALID_NAME),
00222                  errmsg("\"%s\" is not a valid operator name",
00223                         operatorName)));
00224 
00225     /*
00226      * initialize our *nulls and *values arrays
00227      */
00228     for (i = 0; i < Natts_pg_operator; ++i)
00229     {
00230         nulls[i] = false;
00231         values[i] = (Datum) NULL;       /* redundant, but safe */
00232     }
00233 
00234     /*
00235      * initialize values[] with the operator name and input data types. Note
00236      * that oprcode is set to InvalidOid, indicating it's a shell.
00237      */
00238     namestrcpy(&oname, operatorName);
00239     values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
00240     values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
00241     values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
00242     values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
00243     values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
00244     values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
00245     values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
00246     values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
00247     values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid);
00248     values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid);
00249     values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid);
00250     values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid);
00251     values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
00252     values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
00253 
00254     /*
00255      * open pg_operator
00256      */
00257     pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
00258     tupDesc = pg_operator_desc->rd_att;
00259 
00260     /*
00261      * create a new operator tuple
00262      */
00263     tup = heap_form_tuple(tupDesc, values, nulls);
00264 
00265     /*
00266      * insert our "shell" operator tuple
00267      */
00268     operatorObjectId = simple_heap_insert(pg_operator_desc, tup);
00269 
00270     CatalogUpdateIndexes(pg_operator_desc, tup);
00271 
00272     /* Add dependencies for the entry */
00273     makeOperatorDependencies(tup);
00274 
00275     heap_freetuple(tup);
00276 
00277     /* Post creation hook for new shell operator */
00278     InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
00279 
00280     /*
00281      * Make sure the tuple is visible for subsequent lookups/updates.
00282      */
00283     CommandCounterIncrement();
00284 
00285     /*
00286      * close the operator relation and return the oid.
00287      */
00288     heap_close(pg_operator_desc, RowExclusiveLock);
00289 
00290     return operatorObjectId;
00291 }
00292 
00293 /*
00294  * OperatorCreate
00295  *
00296  * "X" indicates an optional argument (i.e. one that can be NULL or 0)
00297  *      operatorName            name for new operator
00298  *      operatorNamespace       namespace for new operator
00299  *      leftTypeId              X left type ID
00300  *      rightTypeId             X right type ID
00301  *      procedureId             procedure ID for operator
00302  *      commutatorName          X commutator operator
00303  *      negatorName             X negator operator
00304  *      restrictionId           X restriction selectivity procedure ID
00305  *      joinId                  X join selectivity procedure ID
00306  *      canMerge                merge join can be used with this operator
00307  *      canHash                 hash join can be used with this operator
00308  *
00309  * The caller should have validated properties and permissions for the
00310  * objects passed as OID references.  We must handle the commutator and
00311  * negator operator references specially, however, since those need not
00312  * exist beforehand.
00313  *
00314  * This routine gets complicated because it allows the user to
00315  * specify operators that do not exist.  For example, if operator
00316  * "op" is being defined, the negator operator "negop" and the
00317  * commutator "commop" can also be defined without specifying
00318  * any information other than their names.  Since in order to
00319  * add "op" to the PG_OPERATOR catalog, all the Oid's for these
00320  * operators must be placed in the fields of "op", a forward
00321  * declaration is done on the commutator and negator operators.
00322  * This is called creating a shell, and its main effect is to
00323  * create a tuple in the PG_OPERATOR catalog with minimal
00324  * information about the operator (just its name and types).
00325  * Forward declaration is used only for this purpose, it is
00326  * not available to the user as it is for type definition.
00327  */
00328 Oid
00329 OperatorCreate(const char *operatorName,
00330                Oid operatorNamespace,
00331                Oid leftTypeId,
00332                Oid rightTypeId,
00333                Oid procedureId,
00334                List *commutatorName,
00335                List *negatorName,
00336                Oid restrictionId,
00337                Oid joinId,
00338                bool canMerge,
00339                bool canHash)
00340 {
00341     Relation    pg_operator_desc;
00342     HeapTuple   tup;
00343     bool        nulls[Natts_pg_operator];
00344     bool        replaces[Natts_pg_operator];
00345     Datum       values[Natts_pg_operator];
00346     Oid         operatorObjectId;
00347     bool        operatorAlreadyDefined;
00348     Oid         operResultType;
00349     Oid         commutatorId,
00350                 negatorId;
00351     bool        selfCommutator = false;
00352     NameData    oname;
00353     TupleDesc   tupDesc;
00354     int         i;
00355 
00356     /*
00357      * Sanity checks
00358      */
00359     if (!validOperatorName(operatorName))
00360         ereport(ERROR,
00361                 (errcode(ERRCODE_INVALID_NAME),
00362                  errmsg("\"%s\" is not a valid operator name",
00363                         operatorName)));
00364 
00365     if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
00366     {
00367         /* If it's not a binary op, these things mustn't be set: */
00368         if (commutatorName)
00369             ereport(ERROR,
00370                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00371                      errmsg("only binary operators can have commutators")));
00372         if (OidIsValid(joinId))
00373             ereport(ERROR,
00374                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00375                  errmsg("only binary operators can have join selectivity")));
00376         if (canMerge)
00377             ereport(ERROR,
00378                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00379                      errmsg("only binary operators can merge join")));
00380         if (canHash)
00381             ereport(ERROR,
00382                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00383                      errmsg("only binary operators can hash")));
00384     }
00385 
00386     operResultType = get_func_rettype(procedureId);
00387 
00388     if (operResultType != BOOLOID)
00389     {
00390         /* If it's not a boolean op, these things mustn't be set: */
00391         if (negatorName)
00392             ereport(ERROR,
00393                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00394                      errmsg("only boolean operators can have negators")));
00395         if (OidIsValid(restrictionId))
00396             ereport(ERROR,
00397                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00398                      errmsg("only boolean operators can have restriction selectivity")));
00399         if (OidIsValid(joinId))
00400             ereport(ERROR,
00401                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00402                 errmsg("only boolean operators can have join selectivity")));
00403         if (canMerge)
00404             ereport(ERROR,
00405                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00406                      errmsg("only boolean operators can merge join")));
00407         if (canHash)
00408             ereport(ERROR,
00409                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00410                      errmsg("only boolean operators can hash")));
00411     }
00412 
00413     operatorObjectId = OperatorGet(operatorName,
00414                                    operatorNamespace,
00415                                    leftTypeId,
00416                                    rightTypeId,
00417                                    &operatorAlreadyDefined);
00418 
00419     if (operatorAlreadyDefined)
00420         ereport(ERROR,
00421                 (errcode(ERRCODE_DUPLICATE_FUNCTION),
00422                  errmsg("operator %s already exists",
00423                         operatorName)));
00424 
00425     /*
00426      * At this point, if operatorObjectId is not InvalidOid then we are
00427      * filling in a previously-created shell.  Insist that the user own any
00428      * such shell.
00429      */
00430     if (OidIsValid(operatorObjectId) &&
00431         !pg_oper_ownercheck(operatorObjectId, GetUserId()))
00432         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
00433                        operatorName);
00434 
00435     /*
00436      * Set up the other operators.  If they do not currently exist, create
00437      * shells in order to get ObjectId's.
00438      */
00439 
00440     if (commutatorName)
00441     {
00442         /* commutator has reversed arg types */
00443         commutatorId = get_other_operator(commutatorName,
00444                                           rightTypeId, leftTypeId,
00445                                           operatorName, operatorNamespace,
00446                                           leftTypeId, rightTypeId,
00447                                           true);
00448 
00449         /* Permission check: must own other operator */
00450         if (OidIsValid(commutatorId) &&
00451             !pg_oper_ownercheck(commutatorId, GetUserId()))
00452             aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
00453                            NameListToString(commutatorName));
00454 
00455         /*
00456          * self-linkage to this operator; will fix below. Note that only
00457          * self-linkage for commutation makes sense.
00458          */
00459         if (!OidIsValid(commutatorId))
00460             selfCommutator = true;
00461     }
00462     else
00463         commutatorId = InvalidOid;
00464 
00465     if (negatorName)
00466     {
00467         /* negator has same arg types */
00468         negatorId = get_other_operator(negatorName,
00469                                        leftTypeId, rightTypeId,
00470                                        operatorName, operatorNamespace,
00471                                        leftTypeId, rightTypeId,
00472                                        false);
00473 
00474         /* Permission check: must own other operator */
00475         if (OidIsValid(negatorId) &&
00476             !pg_oper_ownercheck(negatorId, GetUserId()))
00477             aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
00478                            NameListToString(negatorName));
00479     }
00480     else
00481         negatorId = InvalidOid;
00482 
00483     /*
00484      * set up values in the operator tuple
00485      */
00486 
00487     for (i = 0; i < Natts_pg_operator; ++i)
00488     {
00489         values[i] = (Datum) NULL;
00490         replaces[i] = true;
00491         nulls[i] = false;
00492     }
00493 
00494     namestrcpy(&oname, operatorName);
00495     values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
00496     values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
00497     values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
00498     values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
00499     values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
00500     values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
00501     values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
00502     values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
00503     values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType);
00504     values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId);
00505     values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId);
00506     values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId);
00507     values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
00508     values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
00509 
00510     pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
00511 
00512     /*
00513      * If we are replacing an operator shell, update; else insert
00514      */
00515     if (operatorObjectId)
00516     {
00517         tup = SearchSysCacheCopy1(OPEROID,
00518                                   ObjectIdGetDatum(operatorObjectId));
00519         if (!HeapTupleIsValid(tup))
00520             elog(ERROR, "cache lookup failed for operator %u",
00521                  operatorObjectId);
00522 
00523         tup = heap_modify_tuple(tup,
00524                                 RelationGetDescr(pg_operator_desc),
00525                                 values,
00526                                 nulls,
00527                                 replaces);
00528 
00529         simple_heap_update(pg_operator_desc, &tup->t_self, tup);
00530     }
00531     else
00532     {
00533         tupDesc = pg_operator_desc->rd_att;
00534         tup = heap_form_tuple(tupDesc, values, nulls);
00535 
00536         operatorObjectId = simple_heap_insert(pg_operator_desc, tup);
00537     }
00538 
00539     /* Must update the indexes in either case */
00540     CatalogUpdateIndexes(pg_operator_desc, tup);
00541 
00542     /* Add dependencies for the entry */
00543     makeOperatorDependencies(tup);
00544 
00545     /* Post creation hook for new operator */
00546     InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
00547 
00548     heap_close(pg_operator_desc, RowExclusiveLock);
00549 
00550     /*
00551      * If a commutator and/or negator link is provided, update the other
00552      * operator(s) to point at this one, if they don't already have a link.
00553      * This supports an alternative style of operator definition wherein the
00554      * user first defines one operator without giving negator or commutator,
00555      * then defines the other operator of the pair with the proper commutator
00556      * or negator attribute.  That style doesn't require creation of a shell,
00557      * and it's the only style that worked right before Postgres version 6.5.
00558      * This code also takes care of the situation where the new operator is
00559      * its own commutator.
00560      */
00561     if (selfCommutator)
00562         commutatorId = operatorObjectId;
00563 
00564     if (OidIsValid(commutatorId) || OidIsValid(negatorId))
00565         OperatorUpd(operatorObjectId, commutatorId, negatorId);
00566 
00567     return operatorObjectId;
00568 }
00569 
00570 /*
00571  * Try to lookup another operator (commutator, etc)
00572  *
00573  * If not found, check to see if it is exactly the operator we are trying
00574  * to define; if so, return InvalidOid.  (Note that this case is only
00575  * sensible for a commutator, so we error out otherwise.)  If it is not
00576  * the same operator, create a shell operator.
00577  */
00578 static Oid
00579 get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
00580                    const char *operatorName, Oid operatorNamespace,
00581                    Oid leftTypeId, Oid rightTypeId, bool isCommutator)
00582 {
00583     Oid         other_oid;
00584     bool        otherDefined;
00585     char       *otherName;
00586     Oid         otherNamespace;
00587     AclResult   aclresult;
00588 
00589     other_oid = OperatorLookup(otherOp,
00590                                otherLeftTypeId,
00591                                otherRightTypeId,
00592                                &otherDefined);
00593 
00594     if (OidIsValid(other_oid))
00595     {
00596         /* other op already in catalogs */
00597         return other_oid;
00598     }
00599 
00600     otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
00601                                                        &otherName);
00602 
00603     if (strcmp(otherName, operatorName) == 0 &&
00604         otherNamespace == operatorNamespace &&
00605         otherLeftTypeId == leftTypeId &&
00606         otherRightTypeId == rightTypeId)
00607     {
00608         /*
00609          * self-linkage to this operator; caller will fix later. Note that
00610          * only self-linkage for commutation makes sense.
00611          */
00612         if (!isCommutator)
00613             ereport(ERROR,
00614                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00615              errmsg("operator cannot be its own negator or sort operator")));
00616         return InvalidOid;
00617     }
00618 
00619     /* not in catalogs, different from operator, so make shell */
00620 
00621     aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(),
00622                                       ACL_CREATE);
00623     if (aclresult != ACLCHECK_OK)
00624         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
00625                        get_namespace_name(otherNamespace));
00626 
00627     other_oid = OperatorShellMake(otherName,
00628                                   otherNamespace,
00629                                   otherLeftTypeId,
00630                                   otherRightTypeId);
00631     return other_oid;
00632 }
00633 
00634 /*
00635  * OperatorUpd
00636  *
00637  *  For a given operator, look up its negator and commutator operators.
00638  *  If they are defined, but their negator and commutator fields
00639  *  (respectively) are empty, then use the new operator for neg or comm.
00640  *  This solves a problem for users who need to insert two new operators
00641  *  which are the negator or commutator of each other.
00642  */
00643 static void
00644 OperatorUpd(Oid baseId, Oid commId, Oid negId)
00645 {
00646     int         i;
00647     Relation    pg_operator_desc;
00648     HeapTuple   tup;
00649     bool        nulls[Natts_pg_operator];
00650     bool        replaces[Natts_pg_operator];
00651     Datum       values[Natts_pg_operator];
00652 
00653     for (i = 0; i < Natts_pg_operator; ++i)
00654     {
00655         values[i] = (Datum) 0;
00656         replaces[i] = false;
00657         nulls[i] = false;
00658     }
00659 
00660     /*
00661      * check and update the commutator & negator, if necessary
00662      *
00663      * We need a CommandCounterIncrement here in case of a self-commutator
00664      * operator: we'll need to update the tuple that we just inserted.
00665      */
00666     CommandCounterIncrement();
00667 
00668     pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
00669 
00670     tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(commId));
00671 
00672     /*
00673      * if the commutator and negator are the same operator, do one update. XXX
00674      * this is probably useless code --- I doubt it ever makes sense for
00675      * commutator and negator to be the same thing...
00676      */
00677     if (commId == negId)
00678     {
00679         if (HeapTupleIsValid(tup))
00680         {
00681             Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
00682 
00683             if (!OidIsValid(t->oprcom) || !OidIsValid(t->oprnegate))
00684             {
00685                 if (!OidIsValid(t->oprnegate))
00686                 {
00687                     values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
00688                     replaces[Anum_pg_operator_oprnegate - 1] = true;
00689                 }
00690 
00691                 if (!OidIsValid(t->oprcom))
00692                 {
00693                     values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
00694                     replaces[Anum_pg_operator_oprcom - 1] = true;
00695                 }
00696 
00697                 tup = heap_modify_tuple(tup,
00698                                         RelationGetDescr(pg_operator_desc),
00699                                         values,
00700                                         nulls,
00701                                         replaces);
00702 
00703                 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
00704 
00705                 CatalogUpdateIndexes(pg_operator_desc, tup);
00706             }
00707         }
00708 
00709         heap_close(pg_operator_desc, RowExclusiveLock);
00710 
00711         return;
00712     }
00713 
00714     /* if commutator and negator are different, do two updates */
00715 
00716     if (HeapTupleIsValid(tup) &&
00717         !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
00718     {
00719         values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
00720         replaces[Anum_pg_operator_oprcom - 1] = true;
00721 
00722         tup = heap_modify_tuple(tup,
00723                                 RelationGetDescr(pg_operator_desc),
00724                                 values,
00725                                 nulls,
00726                                 replaces);
00727 
00728         simple_heap_update(pg_operator_desc, &tup->t_self, tup);
00729 
00730         CatalogUpdateIndexes(pg_operator_desc, tup);
00731 
00732         values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
00733         replaces[Anum_pg_operator_oprcom - 1] = false;
00734     }
00735 
00736     /* check and update the negator, if necessary */
00737 
00738     tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(negId));
00739 
00740     if (HeapTupleIsValid(tup) &&
00741         !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
00742     {
00743         values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
00744         replaces[Anum_pg_operator_oprnegate - 1] = true;
00745 
00746         tup = heap_modify_tuple(tup,
00747                                 RelationGetDescr(pg_operator_desc),
00748                                 values,
00749                                 nulls,
00750                                 replaces);
00751 
00752         simple_heap_update(pg_operator_desc, &tup->t_self, tup);
00753 
00754         CatalogUpdateIndexes(pg_operator_desc, tup);
00755     }
00756 
00757     heap_close(pg_operator_desc, RowExclusiveLock);
00758 }
00759 
00760 /*
00761  * Create dependencies for a new operator (either a freshly inserted
00762  * complete operator, a new shell operator, or a just-updated shell).
00763  *
00764  * NB: the OidIsValid tests in this routine are necessary, in case
00765  * the given operator is a shell.
00766  */
00767 static void
00768 makeOperatorDependencies(HeapTuple tuple)
00769 {
00770     Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
00771     ObjectAddress myself,
00772                 referenced;
00773 
00774     myself.classId = OperatorRelationId;
00775     myself.objectId = HeapTupleGetOid(tuple);
00776     myself.objectSubId = 0;
00777 
00778     /*
00779      * In case we are updating a shell, delete any existing entries, except
00780      * for extension membership which should remain the same.
00781      */
00782     deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
00783     deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0);
00784 
00785     /* Dependency on namespace */
00786     if (OidIsValid(oper->oprnamespace))
00787     {
00788         referenced.classId = NamespaceRelationId;
00789         referenced.objectId = oper->oprnamespace;
00790         referenced.objectSubId = 0;
00791         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00792     }
00793 
00794     /* Dependency on left type */
00795     if (OidIsValid(oper->oprleft))
00796     {
00797         referenced.classId = TypeRelationId;
00798         referenced.objectId = oper->oprleft;
00799         referenced.objectSubId = 0;
00800         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00801     }
00802 
00803     /* Dependency on right type */
00804     if (OidIsValid(oper->oprright))
00805     {
00806         referenced.classId = TypeRelationId;
00807         referenced.objectId = oper->oprright;
00808         referenced.objectSubId = 0;
00809         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00810     }
00811 
00812     /* Dependency on result type */
00813     if (OidIsValid(oper->oprresult))
00814     {
00815         referenced.classId = TypeRelationId;
00816         referenced.objectId = oper->oprresult;
00817         referenced.objectSubId = 0;
00818         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00819     }
00820 
00821     /*
00822      * NOTE: we do not consider the operator to depend on the associated
00823      * operators oprcom and oprnegate. We would not want to delete this
00824      * operator if those go away, but only reset the link fields; which is not
00825      * a function that the dependency code can presently handle.  (Something
00826      * could perhaps be done with objectSubId though.)  For now, it's okay to
00827      * let those links dangle if a referenced operator is removed.
00828      */
00829 
00830     /* Dependency on implementation function */
00831     if (OidIsValid(oper->oprcode))
00832     {
00833         referenced.classId = ProcedureRelationId;
00834         referenced.objectId = oper->oprcode;
00835         referenced.objectSubId = 0;
00836         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00837     }
00838 
00839     /* Dependency on restriction selectivity function */
00840     if (OidIsValid(oper->oprrest))
00841     {
00842         referenced.classId = ProcedureRelationId;
00843         referenced.objectId = oper->oprrest;
00844         referenced.objectSubId = 0;
00845         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00846     }
00847 
00848     /* Dependency on join selectivity function */
00849     if (OidIsValid(oper->oprjoin))
00850     {
00851         referenced.classId = ProcedureRelationId;
00852         referenced.objectId = oper->oprjoin;
00853         referenced.objectSubId = 0;
00854         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00855     }
00856 
00857     /* Dependency on owner */
00858     recordDependencyOnOwner(OperatorRelationId, HeapTupleGetOid(tuple),
00859                             oper->oprowner);
00860 
00861     /* Dependency on extension */
00862     recordDependencyOnCurrentExtension(&myself, true);
00863 }