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

Generated by: LCOV version 1.14