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

Generated by: LCOV version 1.14