LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_operator.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 89.6 % 259 232
Test Date: 2026-03-14 06:14:53 Functions: 100.0 % 9 9
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-2026, 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         1068 : validOperatorName(const char *name)
      69              : {
      70         1068 :     size_t      len = strlen(name);
      71              : 
      72              :     /* Can't be empty or too long */
      73         1068 :     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         1068 :     if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
      79            0 :         return false;
      80              : 
      81              :     /* Can't contain slash-star or dash-dash (comment starts) */
      82         1068 :     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         1068 :     if (len > 1 &&
      93          732 :         (name[len - 1] == '+' ||
      94          732 :          name[len - 1] == '-'))
      95              :     {
      96              :         int         ic;
      97              : 
      98            8 :         for (ic = len - 2; ic >= 0; ic--)
      99              :         {
     100            8 :             if (strchr("~!@#^&|`?%", name[ic]))
     101            4 :                 break;
     102              :         }
     103            4 :         if (ic < 0)
     104            0 :             return false;       /* nope, not valid */
     105              :     }
     106              : 
     107              :     /* != isn't valid either, because parser will convert it to <> */
     108         1068 :     if (strcmp(name, "!=") == 0)
     109            0 :         return false;
     110              : 
     111         1068 :     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          790 : 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          790 :     tup = SearchSysCache4(OPERNAMENSP,
     134              :                           PointerGetDatum(operatorName),
     135              :                           ObjectIdGetDatum(leftObjectId),
     136              :                           ObjectIdGetDatum(rightObjectId),
     137              :                           ObjectIdGetDatum(operatorNamespace));
     138          790 :     if (HeapTupleIsValid(tup))
     139              :     {
     140          264 :         Form_pg_operator oprform = (Form_pg_operator) GETSTRUCT(tup);
     141              : 
     142          264 :         operatorObjectId = oprform->oid;
     143          264 :         *defined = RegProcedureIsValid(oprform->oprcode);
     144          264 :         ReleaseSysCache(tup);
     145              :     }
     146              :     else
     147              :     {
     148          526 :         operatorObjectId = InvalidOid;
     149          526 :         *defined = false;
     150              :     }
     151              : 
     152          790 :     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          892 : OperatorLookup(List *operatorName,
     165              :                Oid leftObjectId,
     166              :                Oid rightObjectId,
     167              :                bool *defined)
     168              : {
     169              :     Oid         operatorObjectId;
     170              :     RegProcedure oprcode;
     171              : 
     172          892 :     operatorObjectId = LookupOperName(NULL, operatorName,
     173              :                                       leftObjectId, rightObjectId,
     174              :                                       true, -1);
     175          892 :     if (!OidIsValid(operatorObjectId))
     176              :     {
     177          397 :         *defined = false;
     178          397 :         return InvalidOid;
     179              :     }
     180              : 
     181          495 :     oprcode = get_opcode(operatorObjectId);
     182          495 :     *defined = RegProcedureIsValid(oprcode);
     183              : 
     184          495 :     return operatorObjectId;
     185              : }
     186              : 
     187              : 
     188              : /*
     189              :  * OperatorShellMake
     190              :  *      Make a "shell" entry for a not-yet-existing operator.
     191              :  */
     192              : static Oid
     193          278 : 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          278 :     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          278 :     pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
     220          278 :     tupDesc = pg_operator_desc->rd_att;
     221              : 
     222              :     /*
     223              :      * initialize our *nulls and *values arrays
     224              :      */
     225         4448 :     for (i = 0; i < Natts_pg_operator; ++i)
     226              :     {
     227         4170 :         nulls[i] = false;
     228         4170 :         values[i] = (Datum) 0;  /* 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          278 :     operatorObjectId = GetNewOidWithIndex(pg_operator_desc, OperatorOidIndexId,
     236              :                                           Anum_pg_operator_oid);
     237          278 :     values[Anum_pg_operator_oid - 1] = ObjectIdGetDatum(operatorObjectId);
     238          278 :     namestrcpy(&oname, operatorName);
     239          278 :     values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
     240          278 :     values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
     241          278 :     values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
     242          278 :     values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
     243          278 :     values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
     244          278 :     values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
     245          278 :     values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
     246          278 :     values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
     247          278 :     values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid);
     248          278 :     values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid);
     249          278 :     values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid);
     250          278 :     values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid);
     251          278 :     values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
     252          278 :     values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
     253              : 
     254              :     /*
     255              :      * create a new operator tuple
     256              :      */
     257          278 :     tup = heap_form_tuple(tupDesc, values, nulls);
     258              : 
     259              :     /*
     260              :      * insert our "shell" operator tuple
     261              :      */
     262          278 :     CatalogTupleInsert(pg_operator_desc, tup);
     263              : 
     264              :     /* Add dependencies for the entry */
     265          278 :     makeOperatorDependencies(tup, true, false);
     266              : 
     267          278 :     heap_freetuple(tup);
     268              : 
     269              :     /* Post creation hook for new shell operator */
     270          278 :     InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
     271              : 
     272              :     /*
     273              :      * Make sure the tuple is visible for subsequent lookups/updates.
     274              :      */
     275          278 :     CommandCounterIncrement();
     276              : 
     277              :     /*
     278              :      * close the operator relation and return the oid.
     279              :      */
     280          278 :     table_close(pg_operator_desc, RowExclusiveLock);
     281              : 
     282          278 :     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          790 : 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          790 :     bool        selfCommutator = false;
     345              :     NameData    oname;
     346              :     int         i;
     347              :     ObjectAddress address;
     348              : 
     349              :     /*
     350              :      * Sanity checks
     351              :      */
     352          790 :     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          790 :     operResultType = get_func_rettype(procedureId);
     359              : 
     360          790 :     OperatorValidateParams(leftTypeId,
     361              :                            rightTypeId,
     362              :                            operResultType,
     363              :                            commutatorName != NIL,
     364              :                            negatorName != NIL,
     365              :                            OidIsValid(restrictionId),
     366              :                            OidIsValid(joinId),
     367              :                            canMerge,
     368              :                            canHash);
     369              : 
     370          790 :     operatorObjectId = OperatorGet(operatorName,
     371              :                                    operatorNamespace,
     372              :                                    leftTypeId,
     373              :                                    rightTypeId,
     374              :                                    &operatorAlreadyDefined);
     375              : 
     376          790 :     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          790 :     if (OidIsValid(operatorObjectId) &&
     388          264 :         !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          790 :     if (commutatorName)
     398              :     {
     399              :         /* commutator has reversed arg types */
     400          524 :         commutatorId = get_other_operator(commutatorName,
     401              :                                           rightTypeId, leftTypeId,
     402              :                                           operatorName, operatorNamespace,
     403              :                                           leftTypeId, rightTypeId);
     404              : 
     405              :         /* Permission check: must own other operator */
     406          524 :         if (OidIsValid(commutatorId) &&
     407          408 :             !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          524 :         if (!OidIsValid(commutatorId))
     417          116 :             selfCommutator = true;
     418              :     }
     419              :     else
     420          266 :         commutatorId = InvalidOid;
     421              : 
     422          790 :     if (negatorName)
     423              :     {
     424              :         /* negator has same arg types */
     425          341 :         negatorId = get_other_operator(negatorName,
     426              :                                        leftTypeId, rightTypeId,
     427              :                                        operatorName, operatorNamespace,
     428              :                                        leftTypeId, rightTypeId);
     429              : 
     430              :         /* Permission check: must own other operator */
     431          341 :         if (OidIsValid(negatorId) &&
     432          338 :             !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          341 :         if (!OidIsValid(negatorId) || negatorId == operatorObjectId)
     443            6 :             ereport(ERROR,
     444              :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     445              :                      errmsg("operator cannot be its own negator")));
     446              :     }
     447              :     else
     448          449 :         negatorId = InvalidOid;
     449              : 
     450              :     /*
     451              :      * set up values in the operator tuple
     452              :      */
     453              : 
     454        12544 :     for (i = 0; i < Natts_pg_operator; ++i)
     455              :     {
     456        11760 :         values[i] = (Datum) 0;
     457        11760 :         replaces[i] = true;
     458        11760 :         nulls[i] = false;
     459              :     }
     460              : 
     461          784 :     namestrcpy(&oname, operatorName);
     462          784 :     values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
     463          784 :     values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
     464          784 :     values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
     465          784 :     values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
     466          784 :     values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
     467          784 :     values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
     468          784 :     values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
     469          784 :     values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
     470          784 :     values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType);
     471          784 :     values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId);
     472          784 :     values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId);
     473          784 :     values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId);
     474          784 :     values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
     475          784 :     values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
     476              : 
     477          784 :     pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
     478              : 
     479              :     /*
     480              :      * If we are replacing an operator shell, update; else insert
     481              :      */
     482          784 :     if (operatorObjectId)
     483              :     {
     484          261 :         isUpdate = true;
     485              : 
     486          261 :         tup = SearchSysCacheCopy1(OPEROID,
     487              :                                   ObjectIdGetDatum(operatorObjectId));
     488          261 :         if (!HeapTupleIsValid(tup))
     489            0 :             elog(ERROR, "cache lookup failed for operator %u",
     490              :                  operatorObjectId);
     491              : 
     492          261 :         replaces[Anum_pg_operator_oid - 1] = false;
     493          261 :         tup = heap_modify_tuple(tup,
     494              :                                 RelationGetDescr(pg_operator_desc),
     495              :                                 values,
     496              :                                 nulls,
     497              :                                 replaces);
     498              : 
     499          261 :         CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
     500              :     }
     501              :     else
     502              :     {
     503          523 :         isUpdate = false;
     504              : 
     505          523 :         operatorObjectId = GetNewOidWithIndex(pg_operator_desc,
     506              :                                               OperatorOidIndexId,
     507              :                                               Anum_pg_operator_oid);
     508          523 :         values[Anum_pg_operator_oid - 1] = ObjectIdGetDatum(operatorObjectId);
     509              : 
     510          523 :         tup = heap_form_tuple(RelationGetDescr(pg_operator_desc),
     511              :                               values, nulls);
     512              : 
     513          523 :         CatalogTupleInsert(pg_operator_desc, tup);
     514              :     }
     515              : 
     516              :     /* Add dependencies for the entry */
     517          784 :     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          783 :     if (selfCommutator)
     531          116 :         commutatorId = operatorObjectId;
     532              : 
     533          783 :     if (OidIsValid(commutatorId) || OidIsValid(negatorId))
     534          559 :         OperatorUpd(operatorObjectId, commutatorId, negatorId, false);
     535              : 
     536              :     /* Post creation hook for new operator */
     537          777 :     InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
     538              : 
     539          777 :     table_close(pg_operator_desc, RowExclusiveLock);
     540              : 
     541          777 :     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         1067 : 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         1067 :     if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
     567              :     {
     568              :         /* If it's not a binary op, these things mustn't be set: */
     569           34 :         if (hasCommutator)
     570            0 :             ereport(ERROR,
     571              :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     572              :                      errmsg("only binary operators can have commutators")));
     573           34 :         if (hasJoinSelectivity)
     574            0 :             ereport(ERROR,
     575              :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     576              :                      errmsg("only binary operators can have join selectivity")));
     577           34 :         if (canMerge)
     578            0 :             ereport(ERROR,
     579              :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     580              :                      errmsg("only binary operators can merge join")));
     581           34 :         if (canHash)
     582            0 :             ereport(ERROR,
     583              :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     584              :                      errmsg("only binary operators can hash")));
     585              :     }
     586              : 
     587         1067 :     if (operResultType != BOOLOID)
     588              :     {
     589              :         /* If it's not a boolean op, these things mustn't be set: */
     590          177 :         if (hasNegator)
     591            0 :             ereport(ERROR,
     592              :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     593              :                      errmsg("only boolean operators can have negators")));
     594          177 :         if (hasRestrictionSelectivity)
     595            0 :             ereport(ERROR,
     596              :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     597              :                      errmsg("only boolean operators can have restriction selectivity")));
     598          177 :         if (hasJoinSelectivity)
     599            0 :             ereport(ERROR,
     600              :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     601              :                      errmsg("only boolean operators can have join selectivity")));
     602          177 :         if (canMerge)
     603            0 :             ereport(ERROR,
     604              :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     605              :                      errmsg("only boolean operators can merge join")));
     606          177 :         if (canHash)
     607            0 :             ereport(ERROR,
     608              :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     609              :                      errmsg("only boolean operators can hash")));
     610              :     }
     611         1067 : }
     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          865 : 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          865 :     other_oid = OperatorLookup(otherOp,
     633              :                                otherLeftTypeId,
     634              :                                otherRightTypeId,
     635              :                                &otherDefined);
     636              : 
     637          865 :     if (OidIsValid(other_oid))
     638              :     {
     639              :         /* other op already in catalogs */
     640          468 :         return other_oid;
     641              :     }
     642              : 
     643          397 :     otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
     644              :                                                        &otherName);
     645              : 
     646          397 :     if (strcmp(otherName, operatorName) == 0 &&
     647          163 :         otherNamespace == operatorNamespace &&
     648          119 :         otherLeftTypeId == leftTypeId &&
     649              :         otherRightTypeId == rightTypeId)
     650              :     {
     651              :         /* self-linkage to new operator; caller must handle this */
     652          119 :         return InvalidOid;
     653              :     }
     654              : 
     655              :     /* not in catalogs, different from operator, so make shell */
     656              : 
     657          278 :     aclresult = object_aclcheck(NamespaceRelationId, otherNamespace, GetUserId(),
     658              :                                 ACL_CREATE);
     659          278 :     if (aclresult != ACLCHECK_OK)
     660            0 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
     661            0 :                        get_namespace_name(otherNamespace));
     662              : 
     663          278 :     other_oid = OperatorShellMake(otherName,
     664              :                                   otherNamespace,
     665              :                                   otherLeftTypeId,
     666              :                                   otherRightTypeId);
     667          278 :     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          770 : 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          770 :     if (!isDelete)
     696          577 :         CommandCounterIncrement();
     697              : 
     698              :     /* Open the relation. */
     699          770 :     pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
     700              : 
     701              :     /* Get a writable copy of the commutator's tuple. */
     702          770 :     if (OidIsValid(commId))
     703          726 :         tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(commId));
     704              :     else
     705           44 :         tup = NULL;
     706              : 
     707              :     /* Update the commutator's tuple if need be. */
     708          770 :     if (HeapTupleIsValid(tup))
     709              :     {
     710          726 :         Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
     711          726 :         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          726 :         if (isDelete && OidIsValid(t->oprcom))
     719              :         {
     720          193 :             t->oprcom = InvalidOid;
     721          193 :             update_commutator = true;
     722              :         }
     723          533 :         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          319 :             if (OidIsValid(t->oprcom))
     733              :             {
     734            6 :                 char       *thirdop = get_opname(t->oprcom);
     735              : 
     736            6 :                 if (thirdop != NULL)
     737            6 :                     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          313 :             t->oprcom = baseId;
     749          313 :             update_commutator = true;
     750              :         }
     751              : 
     752              :         /* If any columns were found to need modification, update tuple. */
     753          720 :         if (update_commutator)
     754              :         {
     755          506 :             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          506 :             CommandCounterIncrement();
     765              :         }
     766              :     }
     767              : 
     768              :     /*
     769              :      * Similarly find and update the negator, if any.
     770              :      */
     771          764 :     if (OidIsValid(negId))
     772          461 :         tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(negId));
     773              :     else
     774          303 :         tup = NULL;
     775              : 
     776          764 :     if (HeapTupleIsValid(tup))
     777              :     {
     778          461 :         Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
     779          461 :         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          461 :         if (isDelete && OidIsValid(t->oprnegate))
     787              :         {
     788          117 :             t->oprnegate = InvalidOid;
     789          117 :             update_negator = true;
     790              :         }
     791          344 :         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          183 :             if (OidIsValid(t->oprnegate))
     801              :             {
     802            6 :                 char       *thirdop = get_opname(t->oprnegate);
     803              : 
     804            6 :                 if (thirdop != NULL)
     805            6 :                     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          177 :             t->oprnegate = baseId;
     817          177 :             update_negator = true;
     818              :         }
     819              : 
     820              :         /* If any columns were found to need modification, update tuple. */
     821          455 :         if (update_negator)
     822              :         {
     823          294 :             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          294 :             if (isDelete)
     832          117 :                 CommandCounterIncrement();
     833              :         }
     834              :     }
     835              : 
     836              :     /* Close relation and release catalog lock. */
     837          758 :     table_close(pg_operator_desc, RowExclusiveLock);
     838          758 : }
     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         1339 : makeOperatorDependencies(HeapTuple tuple,
     854              :                          bool makeExtensionDep,
     855              :                          bool isUpdate)
     856              : {
     857         1339 :     Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
     858              :     ObjectAddress myself,
     859              :                 referenced;
     860              :     ObjectAddresses *addrs;
     861              : 
     862         1339 :     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         1339 :     if (isUpdate)
     869              :     {
     870          538 :         deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
     871          538 :         deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0);
     872              :     }
     873              : 
     874         1339 :     addrs = new_object_addresses();
     875              : 
     876              :     /* Dependency on namespace */
     877         1339 :     if (OidIsValid(oper->oprnamespace))
     878              :     {
     879         1339 :         ObjectAddressSet(referenced, NamespaceRelationId, oper->oprnamespace);
     880         1339 :         add_exact_object_address(&referenced, addrs);
     881              :     }
     882              : 
     883              :     /* Dependency on left type */
     884         1339 :     if (OidIsValid(oper->oprleft))
     885              :     {
     886         1305 :         ObjectAddressSet(referenced, TypeRelationId, oper->oprleft);
     887         1305 :         add_exact_object_address(&referenced, addrs);
     888              :     }
     889              : 
     890              :     /* Dependency on right type */
     891         1339 :     if (OidIsValid(oper->oprright))
     892              :     {
     893         1339 :         ObjectAddressSet(referenced, TypeRelationId, oper->oprright);
     894         1339 :         add_exact_object_address(&referenced, addrs);
     895              :     }
     896              : 
     897              :     /* Dependency on result type */
     898         1339 :     if (OidIsValid(oper->oprresult))
     899              :     {
     900         1061 :         ObjectAddressSet(referenced, TypeRelationId, oper->oprresult);
     901         1061 :         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         1339 :     if (OidIsValid(oper->oprcode))
     914              :     {
     915         1061 :         ObjectAddressSet(referenced, ProcedureRelationId, oper->oprcode);
     916         1061 :         add_exact_object_address(&referenced, addrs);
     917              :     }
     918              : 
     919              :     /* Dependency on restriction selectivity function */
     920         1339 :     if (OidIsValid(oper->oprrest))
     921              :     {
     922          752 :         ObjectAddressSet(referenced, ProcedureRelationId, oper->oprrest);
     923          752 :         add_exact_object_address(&referenced, addrs);
     924              :     }
     925              : 
     926              :     /* Dependency on join selectivity function */
     927         1339 :     if (OidIsValid(oper->oprjoin))
     928              :     {
     929          737 :         ObjectAddressSet(referenced, ProcedureRelationId, oper->oprjoin);
     930          737 :         add_exact_object_address(&referenced, addrs);
     931              :     }
     932              : 
     933         1339 :     record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
     934         1339 :     free_object_addresses(addrs);
     935              : 
     936              :     /* Dependency on owner */
     937         1339 :     recordDependencyOnOwner(OperatorRelationId, oper->oid,
     938              :                             oper->oprowner);
     939              : 
     940              :     /* Dependency on extension */
     941         1339 :     if (makeExtensionDep)
     942         1062 :         recordDependencyOnCurrentExtension(&myself, isUpdate);
     943              : 
     944         1338 :     return myself;
     945              : }
        

Generated by: LCOV version 2.0-1