LCOV - code coverage report
Current view: top level - src/backend/commands - operatorcmds.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 92.8 % 264 245
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 6 6
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 75.8 % 244 185

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * operatorcmds.c
       4                 :             :  *
       5                 :             :  *    Routines for operator manipulation commands
       6                 :             :  *
       7                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       9                 :             :  *
      10                 :             :  *
      11                 :             :  * IDENTIFICATION
      12                 :             :  *    src/backend/commands/operatorcmds.c
      13                 :             :  *
      14                 :             :  * DESCRIPTION
      15                 :             :  *    The "DefineFoo" routines take the parse tree and pick out the
      16                 :             :  *    appropriate arguments/flags, passing the results to the
      17                 :             :  *    corresponding "FooCreate" routines (in src/backend/catalog) that do
      18                 :             :  *    the actual catalog-munging.  These routines also verify permission
      19                 :             :  *    of the user to execute the command.
      20                 :             :  *
      21                 :             :  * NOTES
      22                 :             :  *    These things must be defined and committed in the following order:
      23                 :             :  *      "create function":
      24                 :             :  *              input/output, recv/send functions
      25                 :             :  *      "create type":
      26                 :             :  *              type
      27                 :             :  *      "create operator":
      28                 :             :  *              operators
      29                 :             :  *
      30                 :             :  *-------------------------------------------------------------------------
      31                 :             :  */
      32                 :             : #include "postgres.h"
      33                 :             : 
      34                 :             : #include "access/htup_details.h"
      35                 :             : #include "access/table.h"
      36                 :             : #include "catalog/indexing.h"
      37                 :             : #include "catalog/objectaccess.h"
      38                 :             : #include "catalog/pg_namespace.h"
      39                 :             : #include "catalog/pg_operator.h"
      40                 :             : #include "catalog/pg_proc.h"
      41                 :             : #include "catalog/pg_type.h"
      42                 :             : #include "commands/defrem.h"
      43                 :             : #include "miscadmin.h"
      44                 :             : #include "parser/parse_func.h"
      45                 :             : #include "parser/parse_oper.h"
      46                 :             : #include "parser/parse_type.h"
      47                 :             : #include "utils/acl.h"
      48                 :             : #include "utils/lsyscache.h"
      49                 :             : #include "utils/rel.h"
      50                 :             : #include "utils/syscache.h"
      51                 :             : 
      52                 :             : static Oid  ValidateRestrictionEstimator(List *restrictionName);
      53                 :             : static Oid  ValidateJoinEstimator(List *joinName);
      54                 :             : static Oid  ValidateOperatorReference(List *name,
      55                 :             :                                       Oid leftTypeId,
      56                 :             :                                       Oid rightTypeId);
      57                 :             : 
      58                 :             : /*
      59                 :             :  * DefineOperator
      60                 :             :  *      this function extracts all the information from the
      61                 :             :  *      parameter list generated by the parser and then has
      62                 :             :  *      OperatorCreate() do all the actual work.
      63                 :             :  *
      64                 :             :  * 'parameters' is a list of DefElem
      65                 :             :  */
      66                 :             : ObjectAddress
      67                 :         889 : DefineOperator(List *names, List *parameters)
      68                 :             : {
      69                 :             :     char       *oprName;
      70                 :             :     Oid         oprNamespace;
      71                 :             :     AclResult   aclresult;
      72                 :         889 :     bool        canMerge = false;   /* operator merges */
      73                 :         889 :     bool        canHash = false;    /* operator hashes */
      74                 :         889 :     List       *functionName = NIL; /* function for operator */
      75                 :         889 :     TypeName   *typeName1 = NULL;   /* first type name */
      76                 :         889 :     TypeName   *typeName2 = NULL;   /* second type name */
      77                 :         889 :     Oid         typeId1 = InvalidOid;   /* types converted to OID */
      78                 :         889 :     Oid         typeId2 = InvalidOid;
      79                 :             :     Oid         rettype;
      80                 :         889 :     List       *commutatorName = NIL;   /* optional commutator operator name */
      81                 :         889 :     List       *negatorName = NIL;  /* optional negator operator name */
      82                 :         889 :     List       *restrictionName = NIL;  /* optional restrict. sel. function */
      83                 :         889 :     List       *joinName = NIL; /* optional join sel. function */
      84                 :             :     Oid         functionOid;    /* functions converted to OID */
      85                 :             :     Oid         restrictionOid;
      86                 :             :     Oid         joinOid;
      87                 :             :     Oid         typeId[2];      /* to hold left and right arg */
      88                 :             :     int         nargs;
      89                 :             :     ListCell   *pl;
      90                 :             : 
      91                 :             :     /* Convert list of names to a name and namespace */
      92                 :         889 :     oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
      93                 :             : 
      94                 :             :     /* Check we have creation rights in target namespace */
      95                 :         889 :     aclresult = object_aclcheck(NamespaceRelationId, oprNamespace, GetUserId(), ACL_CREATE);
      96         [ +  + ]:         889 :     if (aclresult != ACLCHECK_OK)
      97                 :           4 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
      98                 :           4 :                        get_namespace_name(oprNamespace));
      99                 :             : 
     100                 :             :     /*
     101                 :             :      * loop over the definition list and extract the information we need.
     102                 :             :      */
     103   [ +  -  +  +  :        5570 :     foreach(pl, parameters)
                   +  + ]
     104                 :             :     {
     105                 :        4693 :         DefElem    *defel = (DefElem *) lfirst(pl);
     106                 :             : 
     107         [ +  + ]:        4693 :         if (strcmp(defel->defname, "leftarg") == 0)
     108                 :             :         {
     109                 :         830 :             typeName1 = defGetTypeName(defel);
     110         [ +  + ]:         830 :             if (typeName1->setof)
     111         [ +  - ]:           4 :                 ereport(ERROR,
     112                 :             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     113                 :             :                          errmsg("SETOF type not allowed for operator argument")));
     114                 :             :         }
     115         [ +  + ]:        3863 :         else if (strcmp(defel->defname, "rightarg") == 0)
     116                 :             :         {
     117                 :         869 :             typeName2 = defGetTypeName(defel);
     118         [ +  + ]:         869 :             if (typeName2->setof)
     119         [ +  - ]:           4 :                 ereport(ERROR,
     120                 :             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     121                 :             :                          errmsg("SETOF type not allowed for operator argument")));
     122                 :             :         }
     123                 :             :         /* "function" and "procedure" are equivalent here */
     124         [ +  + ]:        2994 :         else if (strcmp(defel->defname, "function") == 0)
     125                 :          25 :             functionName = defGetQualifiedName(defel);
     126         [ +  + ]:        2969 :         else if (strcmp(defel->defname, "procedure") == 0)
     127                 :         844 :             functionName = defGetQualifiedName(defel);
     128         [ +  + ]:        2125 :         else if (strcmp(defel->defname, "commutator") == 0)
     129                 :         538 :             commutatorName = defGetQualifiedName(defel);
     130         [ +  + ]:        1587 :         else if (strcmp(defel->defname, "negator") == 0)
     131                 :         351 :             negatorName = defGetQualifiedName(defel);
     132         [ +  + ]:        1236 :         else if (strcmp(defel->defname, "restrict") == 0)
     133                 :         533 :             restrictionName = defGetQualifiedName(defel);
     134         [ +  + ]:         703 :         else if (strcmp(defel->defname, "join") == 0)
     135                 :         513 :             joinName = defGetQualifiedName(defel);
     136         [ +  + ]:         190 :         else if (strcmp(defel->defname, "hashes") == 0)
     137                 :          50 :             canHash = defGetBoolean(defel);
     138         [ +  + ]:         140 :         else if (strcmp(defel->defname, "merges") == 0)
     139                 :          80 :             canMerge = defGetBoolean(defel);
     140                 :             :         /* These obsolete options are taken as meaning canMerge */
     141         [ +  + ]:          60 :         else if (strcmp(defel->defname, "sort1") == 0)
     142                 :           6 :             canMerge = true;
     143         [ +  + ]:          54 :         else if (strcmp(defel->defname, "sort2") == 0)
     144                 :           6 :             canMerge = true;
     145         [ +  + ]:          48 :         else if (strcmp(defel->defname, "ltcmp") == 0)
     146                 :           4 :             canMerge = true;
     147         [ +  + ]:          44 :         else if (strcmp(defel->defname, "gtcmp") == 0)
     148                 :           4 :             canMerge = true;
     149                 :             :         else
     150                 :             :         {
     151                 :             :             /* WARNING, not ERROR, for historical backwards-compatibility */
     152         [ +  - ]:          40 :             ereport(WARNING,
     153                 :             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     154                 :             :                      errmsg("operator attribute \"%s\" not recognized",
     155                 :             :                             defel->defname)));
     156                 :             :         }
     157                 :             :     }
     158                 :             : 
     159                 :             :     /*
     160                 :             :      * make sure we have our required definitions
     161                 :             :      */
     162         [ +  + ]:         877 :     if (functionName == NIL)
     163         [ +  - ]:           8 :         ereport(ERROR,
     164                 :             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     165                 :             :                  errmsg("operator function must be specified")));
     166                 :             : 
     167                 :             :     /* Transform type names to type OIDs */
     168         [ +  + ]:         869 :     if (typeName1)
     169                 :         826 :         typeId1 = typenameTypeId(NULL, typeName1);
     170         [ +  + ]:         869 :     if (typeName2)
     171                 :         861 :         typeId2 = typenameTypeId(NULL, typeName2);
     172                 :             : 
     173                 :             :     /*
     174                 :             :      * If only the right argument is missing, the user is likely trying to
     175                 :             :      * create a postfix operator, so give them a hint about why that does not
     176                 :             :      * work.  But if both arguments are missing, do not mention postfix
     177                 :             :      * operators, as the user most likely simply neglected to mention the
     178                 :             :      * arguments.
     179                 :             :      */
     180   [ +  +  +  + ]:         869 :     if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
     181         [ +  - ]:           4 :         ereport(ERROR,
     182                 :             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     183                 :             :                  errmsg("operator argument types must be specified")));
     184         [ +  + ]:         865 :     if (!OidIsValid(typeId2))
     185         [ +  - ]:           4 :         ereport(ERROR,
     186                 :             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     187                 :             :                  errmsg("operator right argument type must be specified"),
     188                 :             :                  errdetail("Postfix operators are not supported.")));
     189                 :             : 
     190         [ +  + ]:         861 :     if (typeName1)
     191                 :             :     {
     192                 :         822 :         aclresult = object_aclcheck(TypeRelationId, typeId1, GetUserId(), ACL_USAGE);
     193         [ +  + ]:         822 :         if (aclresult != ACLCHECK_OK)
     194                 :           8 :             aclcheck_error_type(aclresult, typeId1);
     195                 :             :     }
     196                 :             : 
     197         [ +  - ]:         853 :     if (typeName2)
     198                 :             :     {
     199                 :         853 :         aclresult = object_aclcheck(TypeRelationId, typeId2, GetUserId(), ACL_USAGE);
     200         [ +  + ]:         853 :         if (aclresult != ACLCHECK_OK)
     201                 :           4 :             aclcheck_error_type(aclresult, typeId2);
     202                 :             :     }
     203                 :             : 
     204                 :             :     /*
     205                 :             :      * Look up the operator's underlying function.
     206                 :             :      */
     207         [ +  + ]:         849 :     if (!OidIsValid(typeId1))
     208                 :             :     {
     209                 :          39 :         typeId[0] = typeId2;
     210                 :          39 :         nargs = 1;
     211                 :             :     }
     212         [ -  + ]:         810 :     else if (!OidIsValid(typeId2))
     213                 :             :     {
     214                 :           0 :         typeId[0] = typeId1;
     215                 :           0 :         nargs = 1;
     216                 :             :     }
     217                 :             :     else
     218                 :             :     {
     219                 :         810 :         typeId[0] = typeId1;
     220                 :         810 :         typeId[1] = typeId2;
     221                 :         810 :         nargs = 2;
     222                 :             :     }
     223                 :         849 :     functionOid = LookupFuncName(functionName, nargs, typeId, false);
     224                 :             : 
     225                 :             :     /*
     226                 :             :      * We require EXECUTE rights for the function.  This isn't strictly
     227                 :             :      * necessary, since EXECUTE will be checked at any attempted use of the
     228                 :             :      * operator, but it seems like a good idea anyway.
     229                 :             :      */
     230                 :         849 :     aclresult = object_aclcheck(ProcedureRelationId, functionOid, GetUserId(), ACL_EXECUTE);
     231         [ +  + ]:         849 :     if (aclresult != ACLCHECK_OK)
     232                 :           4 :         aclcheck_error(aclresult, OBJECT_FUNCTION,
     233                 :           4 :                        NameListToString(functionName));
     234                 :             : 
     235                 :         845 :     rettype = get_func_rettype(functionOid);
     236                 :         845 :     aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
     237         [ +  + ]:         845 :     if (aclresult != ACLCHECK_OK)
     238                 :           4 :         aclcheck_error_type(aclresult, rettype);
     239                 :             : 
     240                 :             :     /*
     241                 :             :      * Look up restriction and join estimators if specified
     242                 :             :      */
     243         [ +  + ]:         841 :     if (restrictionName)
     244                 :         533 :         restrictionOid = ValidateRestrictionEstimator(restrictionName);
     245                 :             :     else
     246                 :         308 :         restrictionOid = InvalidOid;
     247         [ +  + ]:         841 :     if (joinName)
     248                 :         513 :         joinOid = ValidateJoinEstimator(joinName);
     249                 :             :     else
     250                 :         328 :         joinOid = InvalidOid;
     251                 :             : 
     252                 :             :     /*
     253                 :             :      * now have OperatorCreate do all the work..
     254                 :             :      */
     255                 :             :     return
     256                 :         841 :         OperatorCreate(oprName, /* operator name */
     257                 :             :                        oprNamespace,    /* namespace */
     258                 :             :                        typeId1, /* left type id */
     259                 :             :                        typeId2, /* right type id */
     260                 :             :                        functionOid, /* function for operator */
     261                 :             :                        commutatorName,  /* optional commutator operator name */
     262                 :             :                        negatorName, /* optional negator operator name */
     263                 :             :                        restrictionOid,  /* optional restrict. sel. function */
     264                 :             :                        joinOid, /* optional join sel. function name */
     265                 :             :                        canMerge,    /* operator merges */
     266                 :             :                        canHash);    /* operator hashes */
     267                 :             : }
     268                 :             : 
     269                 :             : /*
     270                 :             :  * Look up a restriction estimator function by name, and verify that it has
     271                 :             :  * the correct signature and we have the permissions to attach it to an
     272                 :             :  * operator.
     273                 :             :  */
     274                 :             : static Oid
     275                 :         763 : ValidateRestrictionEstimator(List *restrictionName)
     276                 :             : {
     277                 :             :     Oid         typeId[4];
     278                 :             :     Oid         restrictionOid;
     279                 :             : 
     280                 :         763 :     typeId[0] = INTERNALOID;    /* PlannerInfo */
     281                 :         763 :     typeId[1] = OIDOID;         /* operator OID */
     282                 :         763 :     typeId[2] = INTERNALOID;    /* args list */
     283                 :         763 :     typeId[3] = INT4OID;        /* varRelid */
     284                 :             : 
     285                 :         763 :     restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
     286                 :             : 
     287                 :             :     /* estimators must return float8 */
     288         [ -  + ]:         759 :     if (get_func_rettype(restrictionOid) != FLOAT8OID)
     289         [ #  # ]:           0 :         ereport(ERROR,
     290                 :             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     291                 :             :                  errmsg("restriction estimator function %s must return type %s",
     292                 :             :                         NameListToString(restrictionName), "float8")));
     293                 :             : 
     294                 :             :     /*
     295                 :             :      * If the estimator is not a built-in function, require superuser
     296                 :             :      * privilege to install it.  This protects against using something that is
     297                 :             :      * not a restriction estimator or has hard-wired assumptions about what
     298                 :             :      * data types it is working with.  (Built-in estimators are required to
     299                 :             :      * defend themselves adequately against unexpected data type choices, but
     300                 :             :      * it seems impractical to expect that of extensions' estimators.)
     301                 :             :      *
     302                 :             :      * If it is built-in, only require EXECUTE rights.
     303                 :             :      */
     304         [ +  + ]:         759 :     if (restrictionOid >= FirstGenbkiObjectId)
     305                 :             :     {
     306         [ -  + ]:          19 :         if (!superuser())
     307         [ #  # ]:           0 :             ereport(ERROR,
     308                 :             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     309                 :             :                      errmsg("must be superuser to specify a non-built-in restriction estimator function")));
     310                 :             :     }
     311                 :             :     else
     312                 :             :     {
     313                 :             :         AclResult   aclresult;
     314                 :             : 
     315                 :         740 :         aclresult = object_aclcheck(ProcedureRelationId, restrictionOid,
     316                 :             :                                     GetUserId(), ACL_EXECUTE);
     317         [ -  + ]:         740 :         if (aclresult != ACLCHECK_OK)
     318                 :           0 :             aclcheck_error(aclresult, OBJECT_FUNCTION,
     319                 :           0 :                            NameListToString(restrictionName));
     320                 :             :     }
     321                 :             : 
     322                 :         759 :     return restrictionOid;
     323                 :             : }
     324                 :             : 
     325                 :             : /*
     326                 :             :  * Look up a join estimator function by name, and verify that it has the
     327                 :             :  * correct signature and we have the permissions to attach it to an
     328                 :             :  * operator.
     329                 :             :  */
     330                 :             : static Oid
     331                 :         743 : ValidateJoinEstimator(List *joinName)
     332                 :             : {
     333                 :             :     Oid         typeId[5];
     334                 :             :     Oid         joinOid;
     335                 :             :     Oid         joinOid2;
     336                 :             : 
     337                 :         743 :     typeId[0] = INTERNALOID;    /* PlannerInfo */
     338                 :         743 :     typeId[1] = OIDOID;         /* operator OID */
     339                 :         743 :     typeId[2] = INTERNALOID;    /* args list */
     340                 :         743 :     typeId[3] = INT2OID;        /* jointype */
     341                 :         743 :     typeId[4] = INTERNALOID;    /* SpecialJoinInfo */
     342                 :             : 
     343                 :             :     /*
     344                 :             :      * As of Postgres 8.4, the preferred signature for join estimators has 5
     345                 :             :      * arguments, but we still allow the old 4-argument form.  Whine about
     346                 :             :      * ambiguity if both forms exist.
     347                 :             :      */
     348                 :         743 :     joinOid = LookupFuncName(joinName, 5, typeId, true);
     349                 :         743 :     joinOid2 = LookupFuncName(joinName, 4, typeId, true);
     350         [ +  + ]:         743 :     if (OidIsValid(joinOid))
     351                 :             :     {
     352         [ -  + ]:         739 :         if (OidIsValid(joinOid2))
     353         [ #  # ]:           0 :             ereport(ERROR,
     354                 :             :                     (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
     355                 :             :                      errmsg("join estimator function %s has multiple matches",
     356                 :             :                             NameListToString(joinName))));
     357                 :             :     }
     358                 :             :     else
     359                 :             :     {
     360                 :           4 :         joinOid = joinOid2;
     361                 :             :         /* If not found, reference the 5-argument signature in error msg */
     362         [ +  - ]:           4 :         if (!OidIsValid(joinOid))
     363                 :           4 :             joinOid = LookupFuncName(joinName, 5, typeId, false);
     364                 :             :     }
     365                 :             : 
     366                 :             :     /* estimators must return float8 */
     367         [ -  + ]:         739 :     if (get_func_rettype(joinOid) != FLOAT8OID)
     368         [ #  # ]:           0 :         ereport(ERROR,
     369                 :             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     370                 :             :                  errmsg("join estimator function %s must return type %s",
     371                 :             :                         NameListToString(joinName), "float8")));
     372                 :             : 
     373                 :             :     /* privilege checks are the same as in ValidateRestrictionEstimator */
     374         [ +  + ]:         739 :     if (joinOid >= FirstGenbkiObjectId)
     375                 :             :     {
     376         [ -  + ]:           5 :         if (!superuser())
     377         [ #  # ]:           0 :             ereport(ERROR,
     378                 :             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     379                 :             :                      errmsg("must be superuser to specify a non-built-in join estimator function")));
     380                 :             :     }
     381                 :             :     else
     382                 :             :     {
     383                 :             :         AclResult   aclresult;
     384                 :             : 
     385                 :         734 :         aclresult = object_aclcheck(ProcedureRelationId, joinOid,
     386                 :             :                                     GetUserId(), ACL_EXECUTE);
     387         [ -  + ]:         734 :         if (aclresult != ACLCHECK_OK)
     388                 :           0 :             aclcheck_error(aclresult, OBJECT_FUNCTION,
     389                 :           0 :                            NameListToString(joinName));
     390                 :             :     }
     391                 :             : 
     392                 :         739 :     return joinOid;
     393                 :             : }
     394                 :             : 
     395                 :             : /*
     396                 :             :  * Look up and return the OID of an operator,
     397                 :             :  * given a possibly-qualified name and left and right type IDs.
     398                 :             :  *
     399                 :             :  * Verifies that the operator is defined (not a shell) and owned by
     400                 :             :  * the current user, so that we have permission to associate it with
     401                 :             :  * the operator being altered.  Rejecting shell operators is a policy
     402                 :             :  * choice to help catch mistakes, rather than something essential.
     403                 :             :  */
     404                 :             : static Oid
     405                 :          36 : ValidateOperatorReference(List *name,
     406                 :             :                           Oid leftTypeId,
     407                 :             :                           Oid rightTypeId)
     408                 :             : {
     409                 :             :     Oid         oid;
     410                 :             :     bool        defined;
     411                 :             : 
     412                 :          36 :     oid = OperatorLookup(name,
     413                 :             :                          leftTypeId,
     414                 :             :                          rightTypeId,
     415                 :             :                          &defined);
     416                 :             : 
     417                 :             :     /* These message strings are chosen to match parse_oper.c */
     418         [ -  + ]:          36 :     if (!OidIsValid(oid))
     419         [ #  # ]:           0 :         ereport(ERROR,
     420                 :             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     421                 :             :                  errmsg("operator does not exist: %s",
     422                 :             :                         op_signature_string(name,
     423                 :             :                                             leftTypeId,
     424                 :             :                                             rightTypeId))));
     425                 :             : 
     426         [ -  + ]:          36 :     if (!defined)
     427         [ #  # ]:           0 :         ereport(ERROR,
     428                 :             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     429                 :             :                  errmsg("operator is only a shell: %s",
     430                 :             :                         op_signature_string(name,
     431                 :             :                                             leftTypeId,
     432                 :             :                                             rightTypeId))));
     433                 :             : 
     434         [ -  + ]:          36 :     if (!object_ownercheck(OperatorRelationId, oid, GetUserId()))
     435                 :           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
     436                 :           0 :                        NameListToString(name));
     437                 :             : 
     438                 :          36 :     return oid;
     439                 :             : }
     440                 :             : 
     441                 :             : 
     442                 :             : /*
     443                 :             :  * Guts of operator deletion.
     444                 :             :  */
     445                 :             : void
     446                 :         427 : RemoveOperatorById(Oid operOid)
     447                 :             : {
     448                 :             :     Relation    relation;
     449                 :             :     HeapTuple   tup;
     450                 :             :     Form_pg_operator op;
     451                 :             : 
     452                 :         427 :     relation = table_open(OperatorRelationId, RowExclusiveLock);
     453                 :             : 
     454                 :         427 :     tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     455         [ -  + ]:         427 :     if (!HeapTupleIsValid(tup)) /* should not happen */
     456         [ #  # ]:           0 :         elog(ERROR, "cache lookup failed for operator %u", operOid);
     457                 :         427 :     op = (Form_pg_operator) GETSTRUCT(tup);
     458                 :             : 
     459                 :             :     /*
     460                 :             :      * Reset links from commutator and negator, if any.  In case of a
     461                 :             :      * self-commutator or self-negator, this means we have to re-fetch the
     462                 :             :      * updated tuple.  (We could optimize away updates on the tuple we're
     463                 :             :      * about to drop, but it doesn't seem worth convoluting the logic for.)
     464                 :             :      */
     465   [ +  +  -  + ]:         427 :     if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
     466                 :             :     {
     467                 :         199 :         OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
     468   [ +  +  -  + ]:         199 :         if (operOid == op->oprcom || operOid == op->oprnegate)
     469                 :             :         {
     470                 :          80 :             ReleaseSysCache(tup);
     471                 :          80 :             tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     472         [ -  + ]:          80 :             if (!HeapTupleIsValid(tup)) /* should not happen */
     473         [ #  # ]:           0 :                 elog(ERROR, "cache lookup failed for operator %u", operOid);
     474                 :             :         }
     475                 :             :     }
     476                 :             : 
     477                 :         427 :     CatalogTupleDelete(relation, &tup->t_self);
     478                 :             : 
     479                 :         427 :     ReleaseSysCache(tup);
     480                 :             : 
     481                 :         427 :     table_close(relation, RowExclusiveLock);
     482                 :         427 : }
     483                 :             : 
     484                 :             : /*
     485                 :             :  * AlterOperator
     486                 :             :  *      routine implementing ALTER OPERATOR <operator> SET (option = ...).
     487                 :             :  *
     488                 :             :  * Currently, only RESTRICT and JOIN estimator functions can be changed.
     489                 :             :  * COMMUTATOR, NEGATOR, MERGES, and HASHES attributes can be set if they
     490                 :             :  * have not been set previously.  (Changing or removing one of these
     491                 :             :  * attributes could invalidate existing plans, which seems more trouble
     492                 :             :  * than it's worth.)
     493                 :             :  */
     494                 :             : ObjectAddress
     495                 :         332 : AlterOperator(AlterOperatorStmt *stmt)
     496                 :             : {
     497                 :             :     ObjectAddress address;
     498                 :             :     Oid         oprId;
     499                 :             :     Relation    catalog;
     500                 :             :     HeapTuple   tup;
     501                 :             :     Form_pg_operator oprForm;
     502                 :             :     int         i;
     503                 :             :     ListCell   *pl;
     504                 :             :     Datum       values[Natts_pg_operator];
     505                 :             :     bool        nulls[Natts_pg_operator];
     506                 :             :     bool        replaces[Natts_pg_operator];
     507                 :         332 :     List       *restrictionName = NIL;  /* optional restrict. sel. function */
     508                 :         332 :     bool        updateRestriction = false;
     509                 :             :     Oid         restrictionOid;
     510                 :         332 :     List       *joinName = NIL; /* optional join sel. function */
     511                 :         332 :     bool        updateJoin = false;
     512                 :             :     Oid         joinOid;
     513                 :         332 :     List       *commutatorName = NIL;   /* optional commutator operator name */
     514                 :             :     Oid         commutatorOid;
     515                 :         332 :     List       *negatorName = NIL;  /* optional negator operator name */
     516                 :             :     Oid         negatorOid;
     517                 :         332 :     bool        canMerge = false;
     518                 :         332 :     bool        updateMerges = false;
     519                 :         332 :     bool        canHash = false;
     520                 :         332 :     bool        updateHashes = false;
     521                 :             : 
     522                 :             :     /* Look up the operator */
     523                 :         332 :     oprId = LookupOperWithArgs(stmt->opername, false);
     524                 :         332 :     catalog = table_open(OperatorRelationId, RowExclusiveLock);
     525                 :         332 :     tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
     526         [ -  + ]:         332 :     if (!HeapTupleIsValid(tup))
     527         [ #  # ]:           0 :         elog(ERROR, "cache lookup failed for operator %u", oprId);
     528                 :         332 :     oprForm = (Form_pg_operator) GETSTRUCT(tup);
     529                 :             : 
     530                 :             :     /* Process options */
     531   [ +  -  +  +  :         886 :     foreach(pl, stmt->options)
                   +  + ]
     532                 :             :     {
     533                 :         558 :         DefElem    *defel = (DefElem *) lfirst(pl);
     534                 :             :         List       *param;
     535                 :             : 
     536         [ +  + ]:         558 :         if (defel->arg == NULL)
     537                 :          42 :             param = NIL;        /* NONE, removes the function */
     538                 :             :         else
     539                 :         516 :             param = defGetQualifiedName(defel);
     540                 :             : 
     541         [ +  + ]:         558 :         if (strcmp(defel->defname, "restrict") == 0)
     542                 :             :         {
     543                 :         242 :             restrictionName = param;
     544                 :         242 :             updateRestriction = true;
     545                 :             :         }
     546         [ +  + ]:         316 :         else if (strcmp(defel->defname, "join") == 0)
     547                 :             :         {
     548                 :         238 :             joinName = param;
     549                 :         238 :             updateJoin = true;
     550                 :             :         }
     551         [ +  + ]:          78 :         else if (strcmp(defel->defname, "commutator") == 0)
     552                 :             :         {
     553                 :          16 :             commutatorName = defGetQualifiedName(defel);
     554                 :             :         }
     555         [ +  + ]:          62 :         else if (strcmp(defel->defname, "negator") == 0)
     556                 :             :         {
     557                 :          20 :             negatorName = defGetQualifiedName(defel);
     558                 :             :         }
     559         [ +  + ]:          42 :         else if (strcmp(defel->defname, "merges") == 0)
     560                 :             :         {
     561                 :          16 :             canMerge = defGetBoolean(defel);
     562                 :          16 :             updateMerges = true;
     563                 :             :         }
     564         [ +  + ]:          26 :         else if (strcmp(defel->defname, "hashes") == 0)
     565                 :             :         {
     566                 :          22 :             canHash = defGetBoolean(defel);
     567                 :          22 :             updateHashes = true;
     568                 :             :         }
     569                 :             : 
     570                 :             :         /*
     571                 :             :          * The rest of the options that CREATE accepts cannot be changed.
     572                 :             :          * Check for them so that we can give a meaningful error message.
     573                 :             :          */
     574         [ +  - ]:           4 :         else if (strcmp(defel->defname, "leftarg") == 0 ||
     575         [ +  - ]:           4 :                  strcmp(defel->defname, "rightarg") == 0 ||
     576         [ +  - ]:           4 :                  strcmp(defel->defname, "function") == 0 ||
     577         [ -  + ]:           4 :                  strcmp(defel->defname, "procedure") == 0)
     578                 :             :         {
     579         [ #  # ]:           0 :             ereport(ERROR,
     580                 :             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     581                 :             :                      errmsg("operator attribute \"%s\" cannot be changed",
     582                 :             :                             defel->defname)));
     583                 :             :         }
     584                 :             :         else
     585         [ +  - ]:           4 :             ereport(ERROR,
     586                 :             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     587                 :             :                      errmsg("operator attribute \"%s\" not recognized",
     588                 :             :                             defel->defname)));
     589                 :             :     }
     590                 :             : 
     591                 :             :     /* Check permissions. Must be owner. */
     592         [ +  + ]:         328 :     if (!object_ownercheck(OperatorRelationId, oprId, GetUserId()))
     593                 :           4 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
     594                 :           4 :                        NameStr(oprForm->oprname));
     595                 :             : 
     596                 :             :     /*
     597                 :             :      * Look up OIDs for any parameters specified
     598                 :             :      */
     599         [ +  + ]:         324 :     if (restrictionName)
     600                 :         230 :         restrictionOid = ValidateRestrictionEstimator(restrictionName);
     601                 :             :     else
     602                 :          94 :         restrictionOid = InvalidOid;
     603         [ +  + ]:         320 :     if (joinName)
     604                 :         230 :         joinOid = ValidateJoinEstimator(joinName);
     605                 :             :     else
     606                 :          90 :         joinOid = InvalidOid;
     607                 :             : 
     608         [ +  + ]:         316 :     if (commutatorName)
     609                 :             :     {
     610                 :             :         /* commutator has reversed arg types */
     611                 :          16 :         commutatorOid = ValidateOperatorReference(commutatorName,
     612                 :             :                                                   oprForm->oprright,
     613                 :             :                                                   oprForm->oprleft);
     614                 :             : 
     615                 :             :         /*
     616                 :             :          * We don't need to do anything extra for a self commutator as in
     617                 :             :          * OperatorCreate, since the operator surely exists already.
     618                 :             :          */
     619                 :             :     }
     620                 :             :     else
     621                 :         300 :         commutatorOid = InvalidOid;
     622                 :             : 
     623         [ +  + ]:         316 :     if (negatorName)
     624                 :             :     {
     625                 :          20 :         negatorOid = ValidateOperatorReference(negatorName,
     626                 :             :                                                oprForm->oprleft,
     627                 :             :                                                oprForm->oprright);
     628                 :             : 
     629                 :             :         /* Must reject self-negation */
     630         [ +  + ]:          20 :         if (negatorOid == oprForm->oid)
     631         [ +  - ]:           4 :             ereport(ERROR,
     632                 :             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     633                 :             :                      errmsg("operator cannot be its own negator")));
     634                 :             :     }
     635                 :             :     else
     636                 :             :     {
     637                 :         296 :         negatorOid = InvalidOid;
     638                 :             :     }
     639                 :             : 
     640                 :             :     /*
     641                 :             :      * Check that we're not changing any attributes that might be depended on
     642                 :             :      * by plans, while allowing no-op updates.
     643                 :             :      */
     644   [ +  +  +  + ]:         312 :     if (OidIsValid(commutatorOid) && OidIsValid(oprForm->oprcom) &&
     645         [ +  + ]:           8 :         commutatorOid != oprForm->oprcom)
     646         [ +  - ]:           4 :         ereport(ERROR,
     647                 :             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     648                 :             :                  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
     649                 :             :                         "commutator")));
     650                 :             : 
     651   [ +  +  +  + ]:         308 :     if (OidIsValid(negatorOid) && OidIsValid(oprForm->oprnegate) &&
     652         [ +  + ]:           8 :         negatorOid != oprForm->oprnegate)
     653         [ +  - ]:           4 :         ereport(ERROR,
     654                 :             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     655                 :             :                  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
     656                 :             :                         "negator")));
     657                 :             : 
     658   [ +  +  +  +  :         304 :     if (updateMerges && oprForm->oprcanmerge && !canMerge)
                   +  + ]
     659         [ +  - ]:           4 :         ereport(ERROR,
     660                 :             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     661                 :             :                  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
     662                 :             :                         "merges")));
     663                 :             : 
     664   [ +  +  +  +  :         300 :     if (updateHashes && oprForm->oprcanhash && !canHash)
                   +  + ]
     665         [ +  - ]:           4 :         ereport(ERROR,
     666                 :             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     667                 :             :                  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
     668                 :             :                         "hashes")));
     669                 :             : 
     670                 :             :     /* Perform additional checks, like OperatorCreate does */
     671                 :         296 :     OperatorValidateParams(oprForm->oprleft,
     672                 :             :                            oprForm->oprright,
     673                 :             :                            oprForm->oprresult,
     674                 :             :                            OidIsValid(commutatorOid),
     675                 :             :                            OidIsValid(negatorOid),
     676                 :             :                            OidIsValid(restrictionOid),
     677                 :             :                            OidIsValid(joinOid),
     678                 :             :                            canMerge,
     679                 :             :                            canHash);
     680                 :             : 
     681                 :             :     /* Update the tuple */
     682         [ +  + ]:        4736 :     for (i = 0; i < Natts_pg_operator; ++i)
     683                 :             :     {
     684                 :        4440 :         values[i] = (Datum) 0;
     685                 :        4440 :         replaces[i] = false;
     686                 :        4440 :         nulls[i] = false;
     687                 :             :     }
     688         [ +  + ]:         296 :     if (updateRestriction)
     689                 :             :     {
     690                 :         234 :         replaces[Anum_pg_operator_oprrest - 1] = true;
     691                 :         234 :         values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionOid);
     692                 :             :     }
     693         [ +  + ]:         296 :     if (updateJoin)
     694                 :             :     {
     695                 :         234 :         replaces[Anum_pg_operator_oprjoin - 1] = true;
     696                 :         234 :         values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
     697                 :             :     }
     698         [ +  + ]:         296 :     if (OidIsValid(commutatorOid))
     699                 :             :     {
     700                 :          12 :         replaces[Anum_pg_operator_oprcom - 1] = true;
     701                 :          12 :         values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorOid);
     702                 :             :     }
     703         [ +  + ]:         296 :     if (OidIsValid(negatorOid))
     704                 :             :     {
     705                 :          12 :         replaces[Anum_pg_operator_oprnegate - 1] = true;
     706                 :          12 :         values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorOid);
     707                 :             :     }
     708         [ +  + ]:         296 :     if (updateMerges)
     709                 :             :     {
     710                 :          12 :         replaces[Anum_pg_operator_oprcanmerge - 1] = true;
     711                 :          12 :         values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
     712                 :             :     }
     713         [ +  + ]:         296 :     if (updateHashes)
     714                 :             :     {
     715                 :          18 :         replaces[Anum_pg_operator_oprcanhash - 1] = true;
     716                 :          18 :         values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
     717                 :             :     }
     718                 :             : 
     719                 :         296 :     tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
     720                 :             :                             values, nulls, replaces);
     721                 :             : 
     722                 :         296 :     CatalogTupleUpdate(catalog, &tup->t_self, tup);
     723                 :             : 
     724                 :         296 :     address = makeOperatorDependencies(tup, false, true);
     725                 :             : 
     726   [ +  +  +  + ]:         296 :     if (OidIsValid(commutatorOid) || OidIsValid(negatorOid))
     727                 :          24 :         OperatorUpd(oprId, commutatorOid, negatorOid, false);
     728                 :             : 
     729         [ -  + ]:         288 :     InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
     730                 :             : 
     731                 :         288 :     table_close(catalog, NoLock);
     732                 :             : 
     733                 :         288 :     return address;
     734                 :             : }
        

Generated by: LCOV version 2.0-1