LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_operator.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 91.7 % 361 331
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 55.4 % 240 133

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

Generated by: LCOV version 2.3.2-1