LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_operator.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 212 253 83.8 %
Date: 2017-09-29 13:40:31 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pg_operator.c
       4             :  *    routines to support manipulation of the pg_operator relation
       5             :  *
       6             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/catalog/pg_operator.c
      12             :  *
      13             :  * NOTES
      14             :  *    these routines moved here from commands/define.c and somewhat cleaned up.
      15             :  *
      16             :  *-------------------------------------------------------------------------
      17             :  */
      18             : #include "postgres.h"
      19             : 
      20             : #include "access/heapam.h"
      21             : #include "access/htup_details.h"
      22             : #include "access/xact.h"
      23             : #include "catalog/dependency.h"
      24             : #include "catalog/indexing.h"
      25             : #include "catalog/namespace.h"
      26             : #include "catalog/objectaccess.h"
      27             : #include "catalog/pg_namespace.h"
      28             : #include "catalog/pg_operator.h"
      29             : #include "catalog/pg_operator_fn.h"
      30             : #include "catalog/pg_proc.h"
      31             : #include "catalog/pg_type.h"
      32             : #include "miscadmin.h"
      33             : #include "parser/parse_oper.h"
      34             : #include "utils/acl.h"
      35             : #include "utils/builtins.h"
      36             : #include "utils/lsyscache.h"
      37             : #include "utils/rel.h"
      38             : #include "utils/syscache.h"
      39             : 
      40             : 
      41             : static Oid OperatorGet(const char *operatorName,
      42             :             Oid operatorNamespace,
      43             :             Oid leftObjectId,
      44             :             Oid rightObjectId,
      45             :             bool *defined);
      46             : 
      47             : static Oid OperatorLookup(List *operatorName,
      48             :                Oid leftObjectId,
      49             :                Oid rightObjectId,
      50             :                bool *defined);
      51             : 
      52             : static Oid OperatorShellMake(const char *operatorName,
      53             :                   Oid operatorNamespace,
      54             :                   Oid leftTypeId,
      55             :                   Oid rightTypeId);
      56             : 
      57             : static Oid get_other_operator(List *otherOp,
      58             :                    Oid otherLeftTypeId, Oid otherRightTypeId,
      59             :                    const char *operatorName, Oid operatorNamespace,
      60             :                    Oid leftTypeId, Oid rightTypeId,
      61             :                    bool isCommutator);
      62             : 
      63             : 
      64             : /*
      65             :  * Check whether a proposed operator name is legal
      66             :  *
      67             :  * This had better match the behavior of parser/scan.l!
      68             :  *
      69             :  * We need this because the parser is not smart enough to check that
      70             :  * the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses
      71             :  * are operator names rather than some other lexical entity.
      72             :  */
      73             : static bool
      74          32 : validOperatorName(const char *name)
      75             : {
      76          32 :     size_t      len = strlen(name);
      77             : 
      78             :     /* Can't be empty or too long */
      79          32 :     if (len == 0 || len >= NAMEDATALEN)
      80           0 :         return false;
      81             : 
      82             :     /* Can't contain any invalid characters */
      83             :     /* Test string here should match op_chars in scan.l */
      84          32 :     if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
      85           0 :         return false;
      86             : 
      87             :     /* Can't contain slash-star or dash-dash (comment starts) */
      88          32 :     if (strstr(name, "/*") || strstr(name, "--"))
      89           0 :         return false;
      90             : 
      91             :     /*
      92             :      * For SQL standard compatibility, '+' and '-' cannot be the last char of
      93             :      * a multi-char operator unless the operator contains chars that are not
      94             :      * in SQL operators. The idea is to lex '=-' as two operators, but not to
      95             :      * forbid operator names like '?-' that could not be sequences of standard
      96             :      * SQL operators.
      97             :      */
      98          56 :     if (len > 1 &&
      99          48 :         (name[len - 1] == '+' ||
     100          24 :          name[len - 1] == '-'))
     101             :     {
     102             :         int         ic;
     103             : 
     104           0 :         for (ic = len - 2; ic >= 0; ic--)
     105             :         {
     106           0 :             if (strchr("~!@#^&|`?%", name[ic]))
     107           0 :                 break;
     108             :         }
     109           0 :         if (ic < 0)
     110           0 :             return false;       /* nope, not valid */
     111             :     }
     112             : 
     113             :     /* != isn't valid either, because parser will convert it to <> */
     114          32 :     if (strcmp(name, "!=") == 0)
     115           0 :         return false;
     116             : 
     117          32 :     return true;
     118             : }
     119             : 
     120             : 
     121             : /*
     122             :  * OperatorGet
     123             :  *
     124             :  *      finds an operator given an exact specification (name, namespace,
     125             :  *      left and right type IDs).
     126             :  *
     127             :  *      *defined is set TRUE if defined (not a shell)
     128             :  */
     129             : static Oid
     130          28 : OperatorGet(const char *operatorName,
     131             :             Oid operatorNamespace,
     132             :             Oid leftObjectId,
     133             :             Oid rightObjectId,
     134             :             bool *defined)
     135             : {
     136             :     HeapTuple   tup;
     137             :     Oid         operatorObjectId;
     138             : 
     139          28 :     tup = SearchSysCache4(OPERNAMENSP,
     140             :                           PointerGetDatum(operatorName),
     141             :                           ObjectIdGetDatum(leftObjectId),
     142             :                           ObjectIdGetDatum(rightObjectId),
     143             :                           ObjectIdGetDatum(operatorNamespace));
     144          28 :     if (HeapTupleIsValid(tup))
     145             :     {
     146           0 :         RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
     147             : 
     148           0 :         operatorObjectId = HeapTupleGetOid(tup);
     149           0 :         *defined = RegProcedureIsValid(oprcode);
     150           0 :         ReleaseSysCache(tup);
     151             :     }
     152             :     else
     153             :     {
     154          28 :         operatorObjectId = InvalidOid;
     155          28 :         *defined = false;
     156             :     }
     157             : 
     158          28 :     return operatorObjectId;
     159             : }
     160             : 
     161             : /*
     162             :  * OperatorLookup
     163             :  *
     164             :  *      looks up an operator given a possibly-qualified name and
     165             :  *      left and right type IDs.
     166             :  *
     167             :  *      *defined is set TRUE if defined (not a shell)
     168             :  */
     169             : static Oid
     170          14 : OperatorLookup(List *operatorName,
     171             :                Oid leftObjectId,
     172             :                Oid rightObjectId,
     173             :                bool *defined)
     174             : {
     175             :     Oid         operatorObjectId;
     176             :     RegProcedure oprcode;
     177             : 
     178          14 :     operatorObjectId = LookupOperName(NULL, operatorName,
     179             :                                       leftObjectId, rightObjectId,
     180             :                                       true, -1);
     181          14 :     if (!OidIsValid(operatorObjectId))
     182             :     {
     183          11 :         *defined = false;
     184          11 :         return InvalidOid;
     185             :     }
     186             : 
     187           3 :     oprcode = get_opcode(operatorObjectId);
     188           3 :     *defined = RegProcedureIsValid(oprcode);
     189             : 
     190           3 :     return operatorObjectId;
     191             : }
     192             : 
     193             : 
     194             : /*
     195             :  * OperatorShellMake
     196             :  *      Make a "shell" entry for a not-yet-existing operator.
     197             :  */
     198             : static Oid
     199           4 : OperatorShellMake(const char *operatorName,
     200             :                   Oid operatorNamespace,
     201             :                   Oid leftTypeId,
     202             :                   Oid rightTypeId)
     203             : {
     204             :     Relation    pg_operator_desc;
     205             :     Oid         operatorObjectId;
     206             :     int         i;
     207             :     HeapTuple   tup;
     208             :     Datum       values[Natts_pg_operator];
     209             :     bool        nulls[Natts_pg_operator];
     210             :     NameData    oname;
     211             :     TupleDesc   tupDesc;
     212             : 
     213             :     /*
     214             :      * validate operator name
     215             :      */
     216           4 :     if (!validOperatorName(operatorName))
     217           0 :         ereport(ERROR,
     218             :                 (errcode(ERRCODE_INVALID_NAME),
     219             :                  errmsg("\"%s\" is not a valid operator name",
     220             :                         operatorName)));
     221             : 
     222             :     /*
     223             :      * initialize our *nulls and *values arrays
     224             :      */
     225          60 :     for (i = 0; i < Natts_pg_operator; ++i)
     226             :     {
     227          56 :         nulls[i] = false;
     228          56 :         values[i] = (Datum) NULL;   /* redundant, but safe */
     229             :     }
     230             : 
     231             :     /*
     232             :      * initialize values[] with the operator name and input data types. Note
     233             :      * that oprcode is set to InvalidOid, indicating it's a shell.
     234             :      */
     235           4 :     namestrcpy(&oname, operatorName);
     236           4 :     values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
     237           4 :     values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
     238           4 :     values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
     239           4 :     values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
     240           4 :     values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
     241           4 :     values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
     242           4 :     values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
     243           4 :     values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
     244           4 :     values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid);
     245           4 :     values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid);
     246           4 :     values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid);
     247           4 :     values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid);
     248           4 :     values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
     249           4 :     values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
     250             : 
     251             :     /*
     252             :      * open pg_operator
     253             :      */
     254           4 :     pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
     255           4 :     tupDesc = pg_operator_desc->rd_att;
     256             : 
     257             :     /*
     258             :      * create a new operator tuple
     259             :      */
     260           4 :     tup = heap_form_tuple(tupDesc, values, nulls);
     261             : 
     262             :     /*
     263             :      * insert our "shell" operator tuple
     264             :      */
     265           4 :     operatorObjectId = CatalogTupleInsert(pg_operator_desc, tup);
     266             : 
     267             :     /* Add dependencies for the entry */
     268           4 :     makeOperatorDependencies(tup, false);
     269             : 
     270           4 :     heap_freetuple(tup);
     271             : 
     272             :     /* Post creation hook for new shell operator */
     273           4 :     InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
     274             : 
     275             :     /*
     276             :      * Make sure the tuple is visible for subsequent lookups/updates.
     277             :      */
     278           4 :     CommandCounterIncrement();
     279             : 
     280             :     /*
     281             :      * close the operator relation and return the oid.
     282             :      */
     283           4 :     heap_close(pg_operator_desc, RowExclusiveLock);
     284             : 
     285           4 :     return operatorObjectId;
     286             : }
     287             : 
     288             : /*
     289             :  * OperatorCreate
     290             :  *
     291             :  * "X" indicates an optional argument (i.e. one that can be NULL or 0)
     292             :  *      operatorName            name for new operator
     293             :  *      operatorNamespace       namespace for new operator
     294             :  *      leftTypeId              X left type ID
     295             :  *      rightTypeId             X right type ID
     296             :  *      procedureId             procedure ID for operator
     297             :  *      commutatorName          X commutator operator
     298             :  *      negatorName             X negator operator
     299             :  *      restrictionId           X restriction selectivity procedure ID
     300             :  *      joinId                  X join selectivity procedure ID
     301             :  *      canMerge                merge join can be used with this operator
     302             :  *      canHash                 hash join can be used with this operator
     303             :  *
     304             :  * The caller should have validated properties and permissions for the
     305             :  * objects passed as OID references.  We must handle the commutator and
     306             :  * negator operator references specially, however, since those need not
     307             :  * exist beforehand.
     308             :  *
     309             :  * This routine gets complicated because it allows the user to
     310             :  * specify operators that do not exist.  For example, if operator
     311             :  * "op" is being defined, the negator operator "negop" and the
     312             :  * commutator "commop" can also be defined without specifying
     313             :  * any information other than their names.  Since in order to
     314             :  * add "op" to the PG_OPERATOR catalog, all the Oid's for these
     315             :  * operators must be placed in the fields of "op", a forward
     316             :  * declaration is done on the commutator and negator operators.
     317             :  * This is called creating a shell, and its main effect is to
     318             :  * create a tuple in the PG_OPERATOR catalog with minimal
     319             :  * information about the operator (just its name and types).
     320             :  * Forward declaration is used only for this purpose, it is
     321             :  * not available to the user as it is for type definition.
     322             :  */
     323             : ObjectAddress
     324          28 : OperatorCreate(const char *operatorName,
     325             :                Oid operatorNamespace,
     326             :                Oid leftTypeId,
     327             :                Oid rightTypeId,
     328             :                Oid procedureId,
     329             :                List *commutatorName,
     330             :                List *negatorName,
     331             :                Oid restrictionId,
     332             :                Oid joinId,
     333             :                bool canMerge,
     334             :                bool canHash)
     335             : {
     336             :     Relation    pg_operator_desc;
     337             :     HeapTuple   tup;
     338             :     bool        isUpdate;
     339             :     bool        nulls[Natts_pg_operator];
     340             :     bool        replaces[Natts_pg_operator];
     341             :     Datum       values[Natts_pg_operator];
     342             :     Oid         operatorObjectId;
     343             :     bool        operatorAlreadyDefined;
     344             :     Oid         operResultType;
     345             :     Oid         commutatorId,
     346             :                 negatorId;
     347          28 :     bool        selfCommutator = false;
     348             :     NameData    oname;
     349             :     int         i;
     350             :     ObjectAddress address;
     351             : 
     352             :     /*
     353             :      * Sanity checks
     354             :      */
     355          28 :     if (!validOperatorName(operatorName))
     356           0 :         ereport(ERROR,
     357             :                 (errcode(ERRCODE_INVALID_NAME),
     358             :                  errmsg("\"%s\" is not a valid operator name",
     359             :                         operatorName)));
     360             : 
     361          28 :     if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
     362             :     {
     363             :         /* If it's not a binary op, these things mustn't be set: */
     364           6 :         if (commutatorName)
     365           0 :             ereport(ERROR,
     366             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     367             :                      errmsg("only binary operators can have commutators")));
     368           6 :         if (OidIsValid(joinId))
     369           0 :             ereport(ERROR,
     370             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     371             :                      errmsg("only binary operators can have join selectivity")));
     372           6 :         if (canMerge)
     373           0 :             ereport(ERROR,
     374             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     375             :                      errmsg("only binary operators can merge join")));
     376           6 :         if (canHash)
     377           0 :             ereport(ERROR,
     378             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     379             :                      errmsg("only binary operators can hash")));
     380             :     }
     381             : 
     382          28 :     operResultType = get_func_rettype(procedureId);
     383             : 
     384          28 :     if (operResultType != BOOLOID)
     385             :     {
     386             :         /* If it's not a boolean op, these things mustn't be set: */
     387          10 :         if (negatorName)
     388           0 :             ereport(ERROR,
     389             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     390             :                      errmsg("only boolean operators can have negators")));
     391          10 :         if (OidIsValid(restrictionId))
     392           0 :             ereport(ERROR,
     393             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     394             :                      errmsg("only boolean operators can have restriction selectivity")));
     395          10 :         if (OidIsValid(joinId))
     396           0 :             ereport(ERROR,
     397             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     398             :                      errmsg("only boolean operators can have join selectivity")));
     399          10 :         if (canMerge)
     400           0 :             ereport(ERROR,
     401             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     402             :                      errmsg("only boolean operators can merge join")));
     403          10 :         if (canHash)
     404           0 :             ereport(ERROR,
     405             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     406             :                      errmsg("only boolean operators can hash")));
     407             :     }
     408             : 
     409          28 :     operatorObjectId = OperatorGet(operatorName,
     410             :                                    operatorNamespace,
     411             :                                    leftTypeId,
     412             :                                    rightTypeId,
     413             :                                    &operatorAlreadyDefined);
     414             : 
     415          28 :     if (operatorAlreadyDefined)
     416           0 :         ereport(ERROR,
     417             :                 (errcode(ERRCODE_DUPLICATE_FUNCTION),
     418             :                  errmsg("operator %s already exists",
     419             :                         operatorName)));
     420             : 
     421             :     /*
     422             :      * At this point, if operatorObjectId is not InvalidOid then we are
     423             :      * filling in a previously-created shell.  Insist that the user own any
     424             :      * such shell.
     425             :      */
     426          28 :     if (OidIsValid(operatorObjectId) &&
     427           0 :         !pg_oper_ownercheck(operatorObjectId, GetUserId()))
     428           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
     429             :                        operatorName);
     430             : 
     431             :     /*
     432             :      * Set up the other operators.  If they do not currently exist, create
     433             :      * shells in order to get ObjectId's.
     434             :      */
     435             : 
     436          28 :     if (commutatorName)
     437             :     {
     438             :         /* commutator has reversed arg types */
     439           9 :         commutatorId = get_other_operator(commutatorName,
     440             :                                           rightTypeId, leftTypeId,
     441             :                                           operatorName, operatorNamespace,
     442             :                                           leftTypeId, rightTypeId,
     443             :                                           true);
     444             : 
     445             :         /* Permission check: must own other operator */
     446          11 :         if (OidIsValid(commutatorId) &&
     447           2 :             !pg_oper_ownercheck(commutatorId, GetUserId()))
     448           0 :             aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
     449           0 :                            NameListToString(commutatorName));
     450             : 
     451             :         /*
     452             :          * self-linkage to this operator; will fix below. Note that only
     453             :          * self-linkage for commutation makes sense.
     454             :          */
     455           9 :         if (!OidIsValid(commutatorId))
     456           7 :             selfCommutator = true;
     457             :     }
     458             :     else
     459          19 :         commutatorId = InvalidOid;
     460             : 
     461          28 :     if (negatorName)
     462             :     {
     463             :         /* negator has same arg types */
     464           5 :         negatorId = get_other_operator(negatorName,
     465             :                                        leftTypeId, rightTypeId,
     466             :                                        operatorName, operatorNamespace,
     467             :                                        leftTypeId, rightTypeId,
     468             :                                        false);
     469             : 
     470             :         /* Permission check: must own other operator */
     471          10 :         if (OidIsValid(negatorId) &&
     472           5 :             !pg_oper_ownercheck(negatorId, GetUserId()))
     473           0 :             aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
     474           0 :                            NameListToString(negatorName));
     475             :     }
     476             :     else
     477          23 :         negatorId = InvalidOid;
     478             : 
     479             :     /*
     480             :      * set up values in the operator tuple
     481             :      */
     482             : 
     483         420 :     for (i = 0; i < Natts_pg_operator; ++i)
     484             :     {
     485         392 :         values[i] = (Datum) NULL;
     486         392 :         replaces[i] = true;
     487         392 :         nulls[i] = false;
     488             :     }
     489             : 
     490          28 :     namestrcpy(&oname, operatorName);
     491          28 :     values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
     492          28 :     values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
     493          28 :     values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
     494          28 :     values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
     495          28 :     values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
     496          28 :     values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
     497          28 :     values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
     498          28 :     values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
     499          28 :     values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType);
     500          28 :     values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId);
     501          28 :     values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId);
     502          28 :     values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId);
     503          28 :     values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
     504          28 :     values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
     505             : 
     506          28 :     pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
     507             : 
     508             :     /*
     509             :      * If we are replacing an operator shell, update; else insert
     510             :      */
     511          28 :     if (operatorObjectId)
     512             :     {
     513           0 :         isUpdate = true;
     514             : 
     515           0 :         tup = SearchSysCacheCopy1(OPEROID,
     516             :                                   ObjectIdGetDatum(operatorObjectId));
     517           0 :         if (!HeapTupleIsValid(tup))
     518           0 :             elog(ERROR, "cache lookup failed for operator %u",
     519             :                  operatorObjectId);
     520             : 
     521           0 :         tup = heap_modify_tuple(tup,
     522             :                                 RelationGetDescr(pg_operator_desc),
     523             :                                 values,
     524             :                                 nulls,
     525             :                                 replaces);
     526             : 
     527           0 :         CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
     528             :     }
     529             :     else
     530             :     {
     531          28 :         isUpdate = false;
     532             : 
     533          28 :         tup = heap_form_tuple(RelationGetDescr(pg_operator_desc),
     534             :                               values, nulls);
     535             : 
     536          28 :         operatorObjectId = CatalogTupleInsert(pg_operator_desc, tup);
     537             :     }
     538             : 
     539             :     /* Add dependencies for the entry */
     540          28 :     address = makeOperatorDependencies(tup, isUpdate);
     541             : 
     542             :     /* Post creation hook for new operator */
     543          28 :     InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
     544             : 
     545          28 :     heap_close(pg_operator_desc, RowExclusiveLock);
     546             : 
     547             :     /*
     548             :      * If a commutator and/or negator link is provided, update the other
     549             :      * operator(s) to point at this one, if they don't already have a link.
     550             :      * This supports an alternative style of operator definition wherein the
     551             :      * user first defines one operator without giving negator or commutator,
     552             :      * then defines the other operator of the pair with the proper commutator
     553             :      * or negator attribute.  That style doesn't require creation of a shell,
     554             :      * and it's the only style that worked right before Postgres version 6.5.
     555             :      * This code also takes care of the situation where the new operator is
     556             :      * its own commutator.
     557             :      */
     558          28 :     if (selfCommutator)
     559           7 :         commutatorId = operatorObjectId;
     560             : 
     561          28 :     if (OidIsValid(commutatorId) || OidIsValid(negatorId))
     562           9 :         OperatorUpd(operatorObjectId, commutatorId, negatorId, false);
     563             : 
     564          28 :     return address;
     565             : }
     566             : 
     567             : /*
     568             :  * Try to lookup another operator (commutator, etc)
     569             :  *
     570             :  * If not found, check to see if it is exactly the operator we are trying
     571             :  * to define; if so, return InvalidOid.  (Note that this case is only
     572             :  * sensible for a commutator, so we error out otherwise.)  If it is not
     573             :  * the same operator, create a shell operator.
     574             :  */
     575             : static Oid
     576          14 : get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
     577             :                    const char *operatorName, Oid operatorNamespace,
     578             :                    Oid leftTypeId, Oid rightTypeId, bool isCommutator)
     579             : {
     580             :     Oid         other_oid;
     581             :     bool        otherDefined;
     582             :     char       *otherName;
     583             :     Oid         otherNamespace;
     584             :     AclResult   aclresult;
     585             : 
     586          14 :     other_oid = OperatorLookup(otherOp,
     587             :                                otherLeftTypeId,
     588             :                                otherRightTypeId,
     589             :                                &otherDefined);
     590             : 
     591          14 :     if (OidIsValid(other_oid))
     592             :     {
     593             :         /* other op already in catalogs */
     594           3 :         return other_oid;
     595             :     }
     596             : 
     597          11 :     otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
     598             :                                                        &otherName);
     599             : 
     600          11 :     if (strcmp(otherName, operatorName) == 0 &&
     601           7 :         otherNamespace == operatorNamespace &&
     602           7 :         otherLeftTypeId == leftTypeId &&
     603             :         otherRightTypeId == rightTypeId)
     604             :     {
     605             :         /*
     606             :          * self-linkage to this operator; caller will fix later. Note that
     607             :          * only self-linkage for commutation makes sense.
     608             :          */
     609           7 :         if (!isCommutator)
     610           0 :             ereport(ERROR,
     611             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     612             :                      errmsg("operator cannot be its own negator or sort operator")));
     613           7 :         return InvalidOid;
     614             :     }
     615             : 
     616             :     /* not in catalogs, different from operator, so make shell */
     617             : 
     618           4 :     aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(),
     619             :                                       ACL_CREATE);
     620           4 :     if (aclresult != ACLCHECK_OK)
     621           0 :         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
     622           0 :                        get_namespace_name(otherNamespace));
     623             : 
     624           4 :     other_oid = OperatorShellMake(otherName,
     625             :                                   otherNamespace,
     626             :                                   otherLeftTypeId,
     627             :                                   otherRightTypeId);
     628           4 :     return other_oid;
     629             : }
     630             : 
     631             : /*
     632             :  * OperatorUpd
     633             :  *
     634             :  *  For a given operator, look up its negator and commutator operators.
     635             :  *  When isDelete is false, update their negator and commutator fields to
     636             :  *  point back to the given operator; when isDelete is true, update those
     637             :  *  fields to no longer point back to the given operator.
     638             :  *
     639             :  *  The !isDelete case solves a problem for users who need to insert two new
     640             :  *  operators that are the negator or commutator of each other, while the
     641             :  *  isDelete case is needed so as not to leave dangling OID links behind
     642             :  *  after dropping an operator.
     643             :  */
     644             : void
     645          13 : OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
     646             : {
     647             :     Relation    pg_operator_desc;
     648             :     HeapTuple   tup;
     649             : 
     650             :     /*
     651             :      * If we're making an operator into its own commutator, then we need a
     652             :      * command-counter increment here, since we've just inserted the tuple
     653             :      * we're about to update.  But when we're dropping an operator, we can
     654             :      * skip this because we're at the beginning of the command.
     655             :      */
     656          13 :     if (!isDelete)
     657           9 :         CommandCounterIncrement();
     658             : 
     659             :     /* Open the relation. */
     660          13 :     pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
     661             : 
     662             :     /* Get a writable copy of the commutator's tuple. */
     663          13 :     if (OidIsValid(commId))
     664          13 :         tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(commId));
     665             :     else
     666           0 :         tup = NULL;
     667             : 
     668             :     /* Update the commutator's tuple if need be. */
     669          13 :     if (HeapTupleIsValid(tup))
     670             :     {
     671          13 :         Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
     672          13 :         bool        update_commutator = false;
     673             : 
     674             :         /*
     675             :          * Out of due caution, we only change the commutator's oprcom field if
     676             :          * it has the exact value we expected: InvalidOid when creating an
     677             :          * operator, or baseId when dropping one.
     678             :          */
     679          13 :         if (isDelete && t->oprcom == baseId)
     680             :         {
     681           4 :             t->oprcom = InvalidOid;
     682           4 :             update_commutator = true;
     683             :         }
     684           9 :         else if (!isDelete && !OidIsValid(t->oprcom))
     685             :         {
     686           9 :             t->oprcom = baseId;
     687           9 :             update_commutator = true;
     688             :         }
     689             : 
     690             :         /* If any columns were found to need modification, update tuple. */
     691          13 :         if (update_commutator)
     692             :         {
     693          13 :             CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
     694             : 
     695             :             /*
     696             :              * Do CCI to make the updated tuple visible.  We must do this in
     697             :              * case the commutator is also the negator.  (Which would be a
     698             :              * logic error on the operator definer's part, but that's not a
     699             :              * good reason to fail here.)  We would need a CCI anyway in the
     700             :              * deletion case for a self-commutator with no negator.
     701             :              */
     702          13 :             CommandCounterIncrement();
     703             :         }
     704             :     }
     705             : 
     706             :     /*
     707             :      * Similarly find and update the negator, if any.
     708             :      */
     709          13 :     if (OidIsValid(negId))
     710           8 :         tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(negId));
     711             :     else
     712           5 :         tup = NULL;
     713             : 
     714          13 :     if (HeapTupleIsValid(tup))
     715             :     {
     716           8 :         Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
     717           8 :         bool        update_negator = false;
     718             : 
     719             :         /*
     720             :          * Out of due caution, we only change the negator's oprnegate field if
     721             :          * it has the exact value we expected: InvalidOid when creating an
     722             :          * operator, or baseId when dropping one.
     723             :          */
     724           8 :         if (isDelete && t->oprnegate == baseId)
     725             :         {
     726           3 :             t->oprnegate = InvalidOid;
     727           3 :             update_negator = true;
     728             :         }
     729           5 :         else if (!isDelete && !OidIsValid(t->oprnegate))
     730             :         {
     731           5 :             t->oprnegate = baseId;
     732           5 :             update_negator = true;
     733             :         }
     734             : 
     735             :         /* If any columns were found to need modification, update tuple. */
     736           8 :         if (update_negator)
     737             :         {
     738           8 :             CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
     739             : 
     740             :             /*
     741             :              * In the deletion case, do CCI to make the updated tuple visible.
     742             :              * We must do this in case the operator is its own negator. (Which
     743             :              * would be a logic error on the operator definer's part, but
     744             :              * that's not a good reason to fail here.)
     745             :              */
     746           8 :             if (isDelete)
     747           3 :                 CommandCounterIncrement();
     748             :         }
     749             :     }
     750             : 
     751             :     /* Close relation and release catalog lock. */
     752          13 :     heap_close(pg_operator_desc, RowExclusiveLock);
     753          13 : }
     754             : 
     755             : /*
     756             :  * Create dependencies for an operator (either a freshly inserted
     757             :  * complete operator, a new shell operator, a just-updated shell,
     758             :  * or an operator that's being modified by ALTER OPERATOR).
     759             :  *
     760             :  * NB: the OidIsValid tests in this routine are necessary, in case
     761             :  * the given operator is a shell.
     762             :  */
     763             : ObjectAddress
     764          38 : makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
     765             : {
     766          38 :     Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
     767             :     ObjectAddress myself,
     768             :                 referenced;
     769             : 
     770          38 :     myself.classId = OperatorRelationId;
     771          38 :     myself.objectId = HeapTupleGetOid(tuple);
     772          38 :     myself.objectSubId = 0;
     773             : 
     774             :     /*
     775             :      * If we are updating the operator, delete any existing entries, except
     776             :      * for extension membership which should remain the same.
     777             :      */
     778          38 :     if (isUpdate)
     779             :     {
     780           6 :         deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
     781           6 :         deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0);
     782             :     }
     783             : 
     784             :     /* Dependency on namespace */
     785          38 :     if (OidIsValid(oper->oprnamespace))
     786             :     {
     787          38 :         referenced.classId = NamespaceRelationId;
     788          38 :         referenced.objectId = oper->oprnamespace;
     789          38 :         referenced.objectSubId = 0;
     790          38 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     791             :     }
     792             : 
     793             :     /* Dependency on left type */
     794          38 :     if (OidIsValid(oper->oprleft))
     795             :     {
     796          35 :         referenced.classId = TypeRelationId;
     797          35 :         referenced.objectId = oper->oprleft;
     798          35 :         referenced.objectSubId = 0;
     799          35 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     800             :     }
     801             : 
     802             :     /* Dependency on right type */
     803          38 :     if (OidIsValid(oper->oprright))
     804             :     {
     805          35 :         referenced.classId = TypeRelationId;
     806          35 :         referenced.objectId = oper->oprright;
     807          35 :         referenced.objectSubId = 0;
     808          35 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     809             :     }
     810             : 
     811             :     /* Dependency on result type */
     812          38 :     if (OidIsValid(oper->oprresult))
     813             :     {
     814          34 :         referenced.classId = TypeRelationId;
     815          34 :         referenced.objectId = oper->oprresult;
     816          34 :         referenced.objectSubId = 0;
     817          34 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     818             :     }
     819             : 
     820             :     /*
     821             :      * NOTE: we do not consider the operator to depend on the associated
     822             :      * operators oprcom and oprnegate. We would not want to delete this
     823             :      * operator if those go away, but only reset the link fields; which is not
     824             :      * a function that the dependency code can presently handle.  (Something
     825             :      * could perhaps be done with objectSubId though.)  For now, it's okay to
     826             :      * let those links dangle if a referenced operator is removed.
     827             :      */
     828             : 
     829             :     /* Dependency on implementation function */
     830          38 :     if (OidIsValid(oper->oprcode))
     831             :     {
     832          34 :         referenced.classId = ProcedureRelationId;
     833          34 :         referenced.objectId = oper->oprcode;
     834          34 :         referenced.objectSubId = 0;
     835          34 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     836             :     }
     837             : 
     838             :     /* Dependency on restriction selectivity function */
     839          38 :     if (OidIsValid(oper->oprrest))
     840             :     {
     841          11 :         referenced.classId = ProcedureRelationId;
     842          11 :         referenced.objectId = oper->oprrest;
     843          11 :         referenced.objectSubId = 0;
     844          11 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     845             :     }
     846             : 
     847             :     /* Dependency on join selectivity function */
     848          38 :     if (OidIsValid(oper->oprjoin))
     849             :     {
     850           9 :         referenced.classId = ProcedureRelationId;
     851           9 :         referenced.objectId = oper->oprjoin;
     852           9 :         referenced.objectSubId = 0;
     853           9 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     854             :     }
     855             : 
     856             :     /* Dependency on owner */
     857          38 :     recordDependencyOnOwner(OperatorRelationId, HeapTupleGetOid(tuple),
     858             :                             oper->oprowner);
     859             : 
     860             :     /* Dependency on extension */
     861          38 :     recordDependencyOnCurrentExtension(&myself, true);
     862             : 
     863          38 :     return myself;
     864             : }

Generated by: LCOV version 1.11