LCOV - code coverage report
Current view: top level - src/backend/commands - operatorcmds.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 94.6 % 350 331
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 6 6
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 71.2 % 274 195

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

Generated by: LCOV version 2.3.2-1