LCOV - differential code coverage report
Current view: top level - src/backend/catalog - pg_operator.c (source / functions) Coverage Total Hit UBC GIC GNC CBC ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 89.4 % 246 220 26 10 4 206 10 4
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 8 8 3 5
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a